From 5c92fac8e1d04559b69d405fa617921b0e7a06ad Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 28 Nov 2011 09:10:11 -0600
Subject: Weighted mean now has extra credit support

---
 lib/grade/grade_category.php |   37 ++++++++++++++++++++++++++++++-------
 1 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index abe6120..f2e2048 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -686,14 +686,20 @@ class grade_category extends grade_object {
             case GRADE_AGGREGATE_WEIGHTED_MEAN: // Weighted average of all existing final grades, weight specified in coef
                 $weightsum = 0;
                 $sum       = 0;
+                $extrasum  = 0;
 
                 foreach ($grade_values as $itemid=>$grade_value) {
 
-                    if ($items[$itemid]->aggregationcoef <= 0) {
+                    $coef = $items[$itemid]->aggregationcoef;
+
+                    if ($coef == 0) {
                         continue;
+                    } else if ($coef < 0) {
+                        $extrasum += ($grade_value / 10);
+                    } else {
+                        $weightsum += $coef;
+                        $sum       += $coef * $grade_value;
                     }
-                    $weightsum += $items[$itemid]->aggregationcoef;
-                    $sum       += $items[$itemid]->aggregationcoef * $grade_value;
                 }
 
                 if ($weightsum == 0) {
@@ -702,6 +708,8 @@ class grade_category extends grade_object {
                 } else {
                     $agg_grade = $sum / $weightsum;
                 }
+
+                $agg_grade += $extrasum;
                 break;
 
             case GRADE_AGGREGATE_WEIGHTED_MEAN2:
@@ -790,9 +798,11 @@ class grade_category extends grade_object {
         //find max grade possible
         $maxes = array();
 
+        $notweightedmean = $this->aggregation != GRADE_AGGREGATE_WEIGHTED_MEAN;
+
         foreach ($items as $item) {
 
-            if ($item->aggregationcoef > 0) {
+            if (($notweightedmean and $item->aggregationcoef > 0) or $item->aggregationcoef < 0) {
                 // extra credit from this activity - does not affect total
                 continue;
             }
@@ -885,10 +895,16 @@ class grade_category extends grade_object {
             $dropped = 0;
 
             foreach ($grade_values as $itemid=>$value) {
+                $coef = $items[$itemid]->aggregationcoef;
+
+                $validextra = (
+                    ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN and $coef < 0) or
+                    $coef > 0
+                );
 
                 if ($dropped < $this->droplow) {
 
-                    if ($extraused and $items[$itemid]->aggregationcoef > 0) {
+                    if ($extraused and $validextra) {
                         // no drop low for extra credits
 
                     } else {
@@ -907,8 +923,14 @@ class grade_category extends grade_object {
             $kept = 0;
 
             foreach ($grade_values as $itemid=>$value) {
+                $coef = $items[$itemid]->aggregationcoef;
+
+                $validextra = (
+                    ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN and $coef < 0) or
+                    $coef > 0
+                );
 
-                if ($extraused and $items[$itemid]->aggregationcoef > 0) {
+                if ($extraused and $validextra) {
                     // we keep all extra credits
 
                 } else if ($kept < $this->keephigh) {
@@ -929,7 +951,8 @@ class grade_category extends grade_object {
     function is_extracredit_used() {
         return ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN2
              or $this->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN
-             or $this->aggregation == GRADE_AGGREGATE_SUM);
+             or $this->aggregation == GRADE_AGGREGATE_SUM
+             or $this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN);
     }
 
     /**
-- 
1.7.1


From 4c4a1c3da640831d59cd98ca76a538a84b22a7bc Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 28 Nov 2011 10:04:42 -0600
Subject: UI now supports weighted mean EC

---
 grade/edit/tree/index.php |   15 ++++++++++++++-
 grade/edit/tree/lib.php   |    9 +++++++++
 2 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php
index 8d88615..e1328f8 100644
--- a/grade/edit/tree/index.php
+++ b/grade/edit/tree/index.php
@@ -294,7 +294,20 @@ if ($data = data_submitted() and confirm_sesskey()) {
             $value = clean_param($value, PARAM_BOOL);
 
             $grade_item = grade_item::fetch(array('id'=>$aid, 'courseid'=>$courseid));
-            $grade_item->aggregationcoef = $value;
+
+            // Weighted Mean special case
+            $parent = $grade_item->load_parent_category();
+            if ($parent->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
+                $oldcoef = $grade_item->aggregationcoef;
+
+                if ($oldcoef < 0 and !$value) {
+                    $grade_item->aggregationcoef = 0;
+                } else {
+                    $grade_item->aggregationcoef = $value ? -1 : $oldcoef;
+                }
+            } else {
+                $grade_item->aggregationcoef = $value;
+            }
 
             $grade_item->update();
             grade_regrade_final_grades($courseid);
diff --git a/grade/edit/tree/lib.php b/grade/edit/tree/lib.php
index 49af487..9e2a09f 100644
--- a/grade/edit/tree/lib.php
+++ b/grade/edit/tree/lib.php
@@ -366,12 +366,21 @@ class grade_edit_tree {
 
         if ((($aggcoef == 'aggregationcoefweight' || $aggcoef == 'aggregationcoef') && $type == 'weight') ||
             ($aggcoef == 'aggregationcoefextraweight' && $type == 'extra')) {
+
+            if ($aggcoef == 'aggregationcoefweight' && $item->aggregationcoef < 0) {
+                return '';
+            }
+
             return '<input type="text" size="6" id="aggregationcoef_'.$item->id.'" name="aggregationcoef_'.$item->id.'"
                 value="'.grade_edit_tree::format_number($item->aggregationcoef).'" />';
         } elseif ($aggcoef == 'aggregationcoefextrasum' && $type == 'extra') {
             $checked = ($item->aggregationcoef > 0) ? 'checked="checked"' : '';
             return '<input type="hidden" name="extracredit_'.$item->id.'" value="0" />
                     <input type="checkbox" id="extracredit_'.$item->id.'" name="extracredit_'.$item->id.'" value="1" '."$checked />\n";
+        } elseif ($aggcoef == 'aggregationcoefweight' && $type == 'extra') {
+            $checked = ($item->aggregationcoef < 0) ? 'checked="checked"' : '';
+            return '<input type="hidden" name="extracredit_'.$item->id.'" value="0" />
+                    <input type="checkbox" id="extracredit_'.$item->id.'" name="extracredit_'.$item->id.'" value="1" '."$checked />\n";
         } else {
             return '';
         }
-- 
1.7.1


From f87a946b909f8959fb0d3b32dd522e036e2165b3 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 28 Nov 2011 10:12:25 -0600
Subject: Helper function for determining if item within cat is ec

---
 lib/grade/grade_category.php |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index f2e2048..a63f8e9 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -888,23 +888,16 @@ class grade_category extends grade_object {
      * @return array Limited grades.
      */
     public function apply_limit_rules(&$grade_values, $items) {
-        $extraused = $this->is_extracredit_used();
 
         if (!empty($this->droplow)) {
             asort($grade_values, SORT_NUMERIC);
             $dropped = 0;
 
             foreach ($grade_values as $itemid=>$value) {
-                $coef = $items[$itemid]->aggregationcoef;
-
-                $validextra = (
-                    ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN and $coef < 0) or
-                    $coef > 0
-                );
 
                 if ($dropped < $this->droplow) {
 
-                    if ($extraused and $validextra) {
+                    if ($this->is_item_extra_credit($items[$itemid])) {
                         // no drop low for extra credits
 
                     } else {
@@ -923,14 +916,8 @@ class grade_category extends grade_object {
             $kept = 0;
 
             foreach ($grade_values as $itemid=>$value) {
-                $coef = $items[$itemid]->aggregationcoef;
-
-                $validextra = (
-                    ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN and $coef < 0) or
-                    $coef > 0
-                );
 
-                if ($extraused and $validextra) {
+                if ($this->is_item_extra_credit($items[$itemid])) {
                     // we keep all extra credits
 
                 } else if ($kept < $this->keephigh) {
@@ -943,6 +930,20 @@ class grade_category extends grade_object {
         }
     }
 
+    function is_item_extra_credit($item) {
+        $extraused = $this->is_extracredit_used();
+
+        if (!$extraused)
+            return false;
+
+        $validextra = (
+            ($this->aggregation != GRADE_AGGREGATE_WEIGHTED_MEAN && $coef > 0) ||
+            $coef < 0
+        );
+
+        return ($extraused && $validextra);
+    }
+
     /**
      * Returns true if category uses extra credit of any kind
      *
-- 
1.7.1


From 0d3b12c5f42037b5222b27d984c4d8a768e1a2cf Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 28 Nov 2011 12:32:38 -0600
Subject: Retain original aggcoef is extra credit is checked

---
 grade/edit/tree/index.php |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php
index e1328f8..a1820c6 100644
--- a/grade/edit/tree/index.php
+++ b/grade/edit/tree/index.php
@@ -297,13 +297,15 @@ if ($data = data_submitted() and confirm_sesskey()) {
 
             // Weighted Mean special case
             $parent = $grade_item->load_parent_category();
+
             if ($parent->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
                 $oldcoef = $grade_item->aggregationcoef;
 
+                // Retain original aggregationcoef if extra credit checked
                 if ($oldcoef < 0 and !$value) {
-                    $grade_item->aggregationcoef = 0;
+                    $grade_item->aggregationcoef = $oldcoef * -1;
                 } else {
-                    $grade_item->aggregationcoef = $value ? -1 : $oldcoef;
+                    $grade_item->aggregationcoef = $value ? abs($oldcoef) * -1 : $oldcoef;
                 }
             } else {
                 $grade_item->aggregationcoef = $value;
-- 
1.7.1


From 34abd1ffe2fbc1eff46b057e10c3cf45b209ea5c Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 28 Nov 2011 12:42:41 -0600
Subject: Condensed conditonal logic around ec checkbox

---
 grade/edit/tree/lib.php |    9 +++------
 1 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/grade/edit/tree/lib.php b/grade/edit/tree/lib.php
index 9e2a09f..de7a009 100644
--- a/grade/edit/tree/lib.php
+++ b/grade/edit/tree/lib.php
@@ -373,12 +373,9 @@ class grade_edit_tree {
 
             return '<input type="text" size="6" id="aggregationcoef_'.$item->id.'" name="aggregationcoef_'.$item->id.'"
                 value="'.grade_edit_tree::format_number($item->aggregationcoef).'" />';
-        } elseif ($aggcoef == 'aggregationcoefextrasum' && $type == 'extra') {
-            $checked = ($item->aggregationcoef > 0) ? 'checked="checked"' : '';
-            return '<input type="hidden" name="extracredit_'.$item->id.'" value="0" />
-                    <input type="checkbox" id="extracredit_'.$item->id.'" name="extracredit_'.$item->id.'" value="1" '."$checked />\n";
-        } elseif ($aggcoef == 'aggregationcoefweight' && $type == 'extra') {
-            $checked = ($item->aggregationcoef < 0) ? 'checked="checked"' : '';
+        } elseif (($aggcoef == 'aggregationcoefextrasum' || $aggcoef == 'aggregationcoefweight') && $type == 'extra') {
+            $valid = ($aggcoef != 'aggregationcoefweight' and $item->aggregationcoef > 0);
+            $checked = ($valid or $item->aggregationcoef < 0) ? 'checked="checked"' : '';
             return '<input type="hidden" name="extracredit_'.$item->id.'" value="0" />
                     <input type="checkbox" id="extracredit_'.$item->id.'" name="extracredit_'.$item->id.'" value="1" '."$checked />\n";
         } else {
-- 
1.7.1


From 58bf89d6ab28f96ea14957abba8ffabc0bdfda34 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 28 Nov 2011 12:54:09 -0600
Subject: Small bug in helper function.

---
 lib/grade/grade_category.php |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index a63f8e9..f9a3adc 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -936,6 +936,8 @@ class grade_category extends grade_object {
         if (!$extraused)
             return false;
 
+        $coef = $item->aggregationcoef;
+
         $validextra = (
             ($this->aggregation != GRADE_AGGREGATE_WEIGHTED_MEAN && $coef > 0) ||
             $coef < 0
-- 
1.7.1


From 2d2d427b98700113d226afc7490d2a4dd5d87e3d Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 14 Dec 2011 11:28:06 -0600
Subject: Fixed a bug in weighted category items

---
 grade/edit/tree/index.php |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php
index a1820c6..9917e77 100644
--- a/grade/edit/tree/index.php
+++ b/grade/edit/tree/index.php
@@ -298,6 +298,11 @@ if ($data = data_submitted() and confirm_sesskey()) {
             // Weighted Mean special case
             $parent = $grade_item->load_parent_category();
 
+            // Make sure about category item's parent category
+            if ($grade_item->itemtype == 'category') {
+                $parent = $parent->load_parent_category();
+            }
+
             if ($parent->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
                 $oldcoef = $grade_item->aggregationcoef;
 
-- 
1.7.1


From 867b3d910a3d4d308d84cc141c4c5337d12790c0 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 14 Dec 2011 13:24:42 -0600
Subject: Small bug with 0 weight value

---
 grade/edit/tree/index.php |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php
index 9917e77..60ba488 100644
--- a/grade/edit/tree/index.php
+++ b/grade/edit/tree/index.php
@@ -309,6 +309,8 @@ if ($data = data_submitted() and confirm_sesskey()) {
                 // Retain original aggregationcoef if extra credit checked
                 if ($oldcoef < 0 and !$value) {
                     $grade_item->aggregationcoef = $oldcoef * -1;
+                } else if ($oldcoef == 0 and $value) {
+                    $grade_item->aggregationcoef = -1;
                 } else {
                     $grade_item->aggregationcoef = $value ? abs($oldcoef) * -1 : $oldcoef;
                 }
-- 
1.7.1


From 2500c277c416a8f446862d50d043ee51d7e7ce1f Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 14 Dec 2011 13:38:01 -0600
Subject: Standardize grade points better

---
 lib/grade/grade_category.php |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index f9a3adc..f7b8dfe 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -695,7 +695,7 @@ class grade_category extends grade_object {
                     if ($coef == 0) {
                         continue;
                     } else if ($coef < 0) {
-                        $extrasum += ($grade_value / 10);
+                        $extrasum += ($grade_value / (100 / $items[$itemid]->grademax));
                     } else {
                         $weightsum += $coef;
                         $sum       += $coef * $grade_value;
-- 
1.7.1


From b14e95a836733c7752168517dd3c1e58e96b8eae Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 14 Dec 2011 14:19:57 -0600
Subject: Include parent in weighted check

---
 lib/grade/grade_category.php |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index f7b8dfe..1f82641 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -695,7 +695,7 @@ class grade_category extends grade_object {
                     if ($coef == 0) {
                         continue;
                     } else if ($coef < 0) {
-                        $extrasum += ($grade_value / (100 / $items[$itemid]->grademax));
+                        $extrasum += ($grade_value / ($this->grade_item->grademax / $items[$itemid]->grademax));
                     } else {
                         $weightsum += $coef;
                         $sum       += $coef * $grade_value;
-- 
1.7.1


From 148872d6498ffd02f3a9c6fffe20615fc356b1de Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 28 Nov 2011 15:19:39 -0600
Subject: Admin option for SWM weighted extra credit

---
 admin/settings/grades.php |    3 +++
 lang/en/grades.php        |    2 ++
 2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index 0d42537..f74165c 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -89,6 +89,9 @@ if (has_capability('moodle/grade:manage', $systemcontext)
         $defaults = array('value'=>GRADE_AGGREGATE_WEIGHTED_MEAN2, 'forced'=>false, 'adv'=>false);
         $temp->add(new admin_setting_gradecat_combo('grade_aggregation', get_string('aggregation', 'grades'), get_string('aggregation_help', 'grades'), $defaults, $options));
 
+        // SWM Extra Credit handling
+        $temp->add(new admin_setting_configcheckbox('grade_swm_extra_credit', get_string('swm_ec', 'grades'), get_string('swm_ec_help', 'grades'), '1'));
+
         $temp->add(new admin_setting_configmultiselect('grade_aggregations_visible', get_string('aggregationsvisible', 'grades'),
                                                        get_string('aggregationsvisiblehelp', 'grades'), $defaultvisible, $options));
 
diff --git a/lang/en/grades.php b/lang/en/grades.php
index b583eff..bb63038 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -606,6 +606,8 @@ $string['submissions'] = 'Submissions';
 $string['submittedon'] = 'Submitted: {$a}';
 $string['switchtofullview'] = 'Switch to full view';
 $string['switchtosimpleview'] = 'Switch to simple view';
+$string['swm_ec'] = 'Weighted SWM ' . $string['aggregationcoefextra'];
+$string['swm_ec_help'] = 'By default, '.$string['aggregationcoefextra'].' in '.$string['aggregateweightedmean2'].' grade category is weighted. Unchecked this option to allow extra credit items to simply add points to the aggregated total.';
 $string['tabs'] = 'Tabs';
 $string['topcategory'] = 'Super category';
 $string['total'] = 'Total';
-- 
1.7.1


From 7c95ecc70ecf309a2d3b2ff4f44df9db2ea2abb7 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 28 Nov 2011 15:19:57 -0600
Subject: Application of the setting.

---
 lib/grade/grade_category.php |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index abe6120..67a4a62 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -709,6 +709,9 @@ class grade_category extends grade_object {
                 // weight is the range of grade (usually grademax)
                 $weightsum = 0;
                 $sum       = null;
+                $extrasum  = 0;
+
+                $weighted_ec = get_config('moodle', 'grade_swm_extra_credit');
 
                 foreach ($grade_values as $itemid=>$grade_value) {
                     $weight = $items[$itemid]->grademax - $items[$itemid]->grademin;
@@ -719,7 +722,11 @@ class grade_category extends grade_object {
 
                     if ($items[$itemid]->aggregationcoef == 0) {
                         $weightsum += $weight;
+                    } elseif (empty($weighted_ec)) {
+                        $extrasum += ($grade_value / 10);
+                        continue;
                     }
+
                     $sum += $weight * $grade_value;
                 }
 
@@ -729,6 +736,8 @@ class grade_category extends grade_object {
                 } else {
                     $agg_grade = $sum / $weightsum;
                 }
+
+                $agg_grade += $extrasum;
                 break;
 
             case GRADE_AGGREGATE_EXTRACREDIT_MEAN: // special average
-- 
1.7.1


From a23d6dc4ad9547fbcb5017466c6917bc6a62ec03 Mon Sep 17 00:00:00 2001
From: Robert Russo <rrusso@lsu.edu>
Date: Wed, 14 Dec 2011 14:35:26 -0600
Subject: Small bugfix in SWM

---
 lib/grade/grade_category.php |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index 67a4a62..02b52c4 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -723,7 +723,7 @@ class grade_category extends grade_object {
                     if ($items[$itemid]->aggregationcoef == 0) {
                         $weightsum += $weight;
                     } elseif (empty($weighted_ec)) {
-                        $extrasum += ($grade_value / 10);
+                        $extrasum += ($grade_value / ($this->grade_item->grademax / $items[$itemid]->grademax));
                         continue;
                     }
 
-- 
1.7.1


From 75967f957f30409a73887ca1fc3e7717f20fd34e Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 5 Dec 2011 08:50:18 -0600
Subject: Adding Admin option for grade cat total override

---
 admin/settings/grades.php |    3 +++
 lang/en/grades.php        |    4 ++++
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index 0d42537..09818ec 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -94,6 +94,9 @@ if (has_capability('moodle/grade:manage', $systemcontext)
 
         $options = array(0 => get_string('no'), 1 => get_string('yes'));
 
+        $temp->add(new admin_setting_configcheckbox('grade_overridecat', get_string('overridecat', 'grades'),
+            get_string('overridecat_help', 'grades'), 1));
+
         $defaults = array('value'=>1, 'forced'=>false, 'adv'=>true);
         $temp->add(new admin_setting_gradecat_combo('grade_aggregateonlygraded', get_string('aggregateonlygraded', 'grades'),
                     get_string('aggregateonlygraded_help', 'grades'), $defaults, $options));
diff --git a/lang/en/grades.php b/lang/en/grades.php
index b583eff..b52e786 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -459,6 +459,10 @@ $string['outcomesstandardavailable'] = 'Available standard outcomes';
 $string['outcomestandard'] = 'Standard outcome';
 $string['outcomestandard_help'] = 'A standard outcome is available site-wide, for all courses.';
 $string['overallaverage'] = 'Overall average';
+$string['overridecat'] = 'Allow Grade Override';
+$string['overridecat_help'] = 'This option allows users to override the final
+grade in for category totals. Unchecking this option will make category totals
+uneditable.';
 $string['overridden'] = 'Overridden';
 $string['overridden_help'] = 'If ticked, the grade can no longer be changed from within the related activity.
 
-- 
1.7.1


From 55f4a27b52d593b90d35aebaea428b08a232d079 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 5 Dec 2011 09:38:20 -0600
Subject: Overriable support in library.

---
 lib/grade/grade_grade.php |    2 +-
 lib/grade/grade_item.php  |    8 +++++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/grade/grade_grade.php b/lib/grade/grade_grade.php
index 3278e7c..e6b6455 100644
--- a/lib/grade/grade_grade.php
+++ b/lib/grade/grade_grade.php
@@ -228,7 +228,7 @@ class grade_grade extends grade_object {
 
         $grade_item = $this->load_grade_item();
 
-        if ($grade_item->gradetype == GRADE_TYPE_NONE) {
+        if ($grade_item->gradetype == GRADE_TYPE_NONE or !$grade_item->is_overridable_item()) {
             return false;
         }
 
diff --git a/lib/grade/grade_item.php b/lib/grade/grade_item.php
index 630e915..12561f6 100644
--- a/lib/grade/grade_item.php
+++ b/lib/grade/grade_item.php
@@ -919,7 +919,13 @@ class grade_item extends grade_object {
      * @return boolean
      */
     public function is_overridable_item() {
-        return !$this->is_outcome_item() and ($this->is_external_item() or $this->is_calculated() or $this->is_course_item() or $this->is_category_item());
+        if ($this->is_course_item() or $this->is_category_item()) {
+            $overridable = (bool) get_config('moodle', 'grade_overridecat');
+        } else {
+            $overridable = true;
+        }
+
+        return !$this->is_outcome_item() and ($this->is_external_item() or $this->is_calculated() or $overridable);
     }
 
     /**
-- 
1.7.1


From e5e6b3f84aedc00acf6e74abc2ee4865041b2220 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 5 Dec 2011 09:38:34 -0600
Subject: Making use of library support for UI

---
 grade/report/grader/lib.php |   11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index bcacf6d..d8acd59 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -903,7 +903,7 @@ class grade_report_grader extends grade_report {
 
                 // Do not show any icons if no grade (no record in DB to match)
                 if (!$item->needsupdate and $USER->gradeediting[$this->courseid]) {
-                    $itemcell->text .= $this->get_icons($element);
+                    $itemcell->text .= $this->get_icons($element, $item);
                 }
 
                 $hidden = '';
@@ -1438,10 +1438,11 @@ class grade_report_grader extends grade_report {
      * figures out the state of the object and builds then returns a div
      * with the icons needed for the grader report.
      *
-     * @param array $object
+     * @param object $object
+     * @param grade_item $item
      * @return string HTML
      */
-    protected function get_icons($element) {
+    protected function get_icons($element, $item = null) {
         global $CFG, $USER, $OUTPUT;
 
         if (!$USER->gradeediting[$this->courseid]) {
@@ -1451,7 +1452,9 @@ class grade_report_grader extends grade_report {
         // Init all icons
         $editicon = '';
 
-        if ($element['type'] != 'categoryitem' && $element['type'] != 'courseitem') {
+        $overridable = $item ? $item->is_overridable_item() : true;
+
+        if ($element['type'] != 'categoryitem' && $element['type'] != 'courseitem' &&$overridable) {
             $editicon = $this->gtree->get_edit_icon($element, $this->gpr);
         }
 
-- 
1.7.1


From d72275f532347d69c2cb100efb4695642a7903e6 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 5 Dec 2011 10:31:11 -0600
Subject: Unmodified get_icons function.

---
 grade/report/grader/lib.php |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index d8acd59..149accb 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -903,7 +903,7 @@ class grade_report_grader extends grade_report {
 
                 // Do not show any icons if no grade (no record in DB to match)
                 if (!$item->needsupdate and $USER->gradeediting[$this->courseid]) {
-                    $itemcell->text .= $this->get_icons($element, $item);
+                    $itemcell->text .= $this->get_icons($element);
                 }
 
                 $hidden = '';
@@ -1439,10 +1439,9 @@ class grade_report_grader extends grade_report {
      * with the icons needed for the grader report.
      *
      * @param object $object
-     * @param grade_item $item
      * @return string HTML
      */
-    protected function get_icons($element, $item = null) {
+    protected function get_icons($element) {
         global $CFG, $USER, $OUTPUT;
 
         if (!$USER->gradeediting[$this->courseid]) {
@@ -1452,7 +1451,13 @@ class grade_report_grader extends grade_report {
         // Init all icons
         $editicon = '';
 
-        $overridable = $item ? $item->is_overridable_item() : true;
+        if ($element['type'] == 'grade') {
+            $item = $element['object']->grade_item;
+
+            $overridable = $item->is_overridable_item();
+        } else {
+            $overridable = true;
+        }
 
         if ($element['type'] != 'categoryitem' && $element['type'] != 'courseitem' &&$overridable) {
             $editicon = $this->gtree->get_edit_icon($element, $this->gpr);
-- 
1.7.1


From fa89895cca2674747d4c577673abb1272907e4f2 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 5 Dec 2011 11:55:47 -0600
Subject: Modified javascript to allow image popout.

---
 grade/report/grader/module.js |   33 +++++++++++++++++++++++++++++++--
 1 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/grade/report/grader/module.js b/grade/report/grader/module.js
index 16f710a..21d5f30 100644
--- a/grade/report/grader/module.js
+++ b/grade/report/grader/module.js
@@ -50,7 +50,7 @@ M.gradereport_grader = {
             show : function(e, report) {
                 e.halt();
 
-                var properties = report.get_cell_info(e.target);
+                var properties = report.get_image_or_cell_info(e.target);
                 if (!properties) {
                     return;
                 }
@@ -127,6 +127,12 @@ M.gradereport_grader.classes.report = function(Y, id, cfg, items, users, feedbac
         if (tr.getAttribute('id').match(/^(fixed_)?user_(\d+)$/)) {
             // Highlight rows
             tr.all('th.cell').on('click', this.table_highlight_row, this, tr);
+            // Popout image
+            tr.all('th.cell div.userpic img.userpicture').each(function(img) {
+                if (img.get('className') === "userpicture") {
+                    M.gradereport_grader.tooltip.attach(img, this);
+                }
+            }, this);
             // Display tooltips
             tr.all('td.cell').each(function(cell){
                 M.gradereport_grader.tooltip.attach(cell, this);
@@ -165,6 +171,29 @@ M.gradereport_grader.classes.report.prototype.users = [];             // Array c
 M.gradereport_grader.classes.report.prototype.feedback = [];          // Array containing feedback items
 M.gradereport_grader.classes.report.prototype.ajaxenabled = false;    // True is AJAX is enabled for the report
 M.gradereport_grader.classes.report.prototype.ajax = null;            // An instance of the ajax class or null
+
+M.gradereport_grader.classes.report.prototype.get_image_or_cell_info = function(arg) {
+    if (arg instanceof this.Y.Node && arg.get('nodeName').toUpperCase() === 'IMG') {
+        return this.get_image_info(arg);
+    } else {
+        return this.get_cell_info(arg);
+    }
+};
+
+M.gradereport_grader.classes.report.prototype.get_image_info = function(img) {
+    var src = img.getAttribute('src');
+
+    var userid = img.ancestor('tr').getAttribute('id').split('_')[2];
+
+    var img_source = "<img class='profile_popout' src='" + src.replace("f2", "f1") + "'/>";
+
+    return {
+        username: this.users[userid],
+        itemname: img_source,
+        cell: img
+    };
+};
+
 /**
  * Highlights a row in the report
  *
@@ -1197,4 +1226,4 @@ for (var i in M.gradereport_grader.classes.textfield.prototype) {
     if (!M.gradereport_grader.classes.scalefield.prototype[i]) {
         M.gradereport_grader.classes.scalefield.prototype[i] = M.gradereport_grader.classes.textfield.prototype[i];
     }
-}
\ No newline at end of file
+}
-- 
1.7.1


From 3156c6ff9eebdc41dde90171749149eddfc66291 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 7 Dec 2011 14:18:25 -0600
Subject: Grade library now supports manual rawgrade

---
 grade/edit/tree/item_form.php |    5 -----
 grade/report/grader/lib.php   |    5 +++++
 lib/grade/grade_item.php      |   14 +++++++++-----
 3 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/grade/edit/tree/item_form.php b/grade/edit/tree/item_form.php
index 642be6b..412b206 100644
--- a/grade/edit/tree/item_form.php
+++ b/grade/edit/tree/item_form.php
@@ -281,11 +281,6 @@ class edit_item_form extends moodleform {
                     }
                 }
             }
-
-        } else {
-            // all new items are manual, children of course category
-            $mform->removeElement('plusfactor');
-            $mform->removeElement('multfactor');
         }
 
         // no parent header for course category
diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index bcacf6d..360c7d3 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -926,6 +926,11 @@ class grade_report_grader extends grade_report {
 
                 } else if ($USER->gradeediting[$this->courseid]) {
 
+                    // Editing means user edit manual item raw
+                    if ($item->is_manual_item()) {
+                        $gradeval = $grade->rawgrade;
+                    }
+
                     if ($item->scaleid && !empty($scalesarray[$item->scaleid])) {
                         $scale = $scalesarray[$item->scaleid];
                         $gradeval = (int)$gradeval; // scales use only integers
diff --git a/lib/grade/grade_item.php b/lib/grade/grade_item.php
index 630e915..0e60942 100644
--- a/lib/grade/grade_item.php
+++ b/lib/grade/grade_item.php
@@ -655,10 +655,6 @@ class grade_item extends grade_object {
                 return "Could not aggregate final grades for category:".$this->id; // TODO: improve and localize
             }
 
-        } else if ($this->is_manual_item()) {
-            // manual items track only final grades, no raw grades
-            return true;
-
         } else if (!$this->is_raw_used()) {
             // hmm - raw grades are not used- nothing to regrade
             return true;
@@ -935,7 +931,7 @@ class grade_item extends grade_object {
      * @return boolean
      */
     public function is_raw_used() {
-        return ($this->is_external_item() and !$this->is_calculated() and !$this->is_outcome_item());
+        return ($this->is_manual_item() or $this->is_external_item() and !$this->is_calculated() and !$this->is_outcome_item());
     }
 
     /**
@@ -1438,6 +1434,14 @@ class grade_item extends grade_object {
             return false;
         }
 
+        // Manual Item raw-grade support
+        if ($this->is_manual_item()) {
+            return $this->update_raw_grade(
+                $userid, $finalgrade, $source, $feedback, $feedbackformat,
+                $usermodified, null, null, $grade
+            );
+        }
+
         $oldgrade = new stdClass();
         $oldgrade->finalgrade     = $grade->finalgrade;
         $oldgrade->overridden     = $grade->overridden;
-- 
1.7.1


From 1f383c6f6b4efa0506d883df603e443a0fbba66a Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 7 Dec 2011 14:25:59 -0600
Subject: Upgrade script for old manual items

---
 grade/report/grader/db/upgrade.php |   69 ++++++++++++++++++++++++++++++++++++
 grade/report/grader/version.php    |    3 +-
 2 files changed, 71 insertions(+), 1 deletions(-)
 create mode 100644 grade/report/grader/db/upgrade.php

diff --git a/grade/report/grader/db/upgrade.php b/grade/report/grader/db/upgrade.php
new file mode 100644
index 0000000..9cdbb4f
--- /dev/null
+++ b/grade/report/grader/db/upgrade.php
@@ -0,0 +1,69 @@
+<?php
+
+function xmldb_gradereport_grader_upgrade($oldversion) {
+
+    $upgrade = new gradereport_grader_upgrade(array(
+        new grader_manual_items()
+    ));
+
+    return $upgrade->from($oldversion);
+}
+
+abstract class gradereport_grader_upgrade_state {
+    var $version;
+
+    abstract function upgrade($db);
+
+    function __invoke($db) {
+        return $this->upgrade($db);
+    }
+}
+
+class grader_manual_items extends gradereport_grader_upgrade_state {
+    var $version = 2011120801;
+
+    function upgrade($db) {
+        $sql = "UPDATE {grade_grades} gr, {grade_items} gi
+            SET gr.rawgrade = gr.finalgrade
+            WHERE gi.id = gr.itemid AND gi.itemtype = 'manual'";
+
+        return $db->execute($sql);
+    }
+}
+
+class gradereport_grader_upgrade {
+    function __construct($upgrades) {
+        $this->upgrades = $upgrades;
+    }
+
+    function from($oldversion) {
+        global $DB;
+
+        // Oldest upgrade first
+        usort($this->upgrades, function($a, $b) {
+            $diff = ($a->version < $b->version) ? -1 : 1;
+            return ($a->version == $b->version) ? 0 : $diff;
+        });
+
+        $result = true;
+
+        foreach ($this->upgrades as $upgrade) {
+            if (!$result) continue;
+
+            if ($oldversion < $upgrade->version and is_callable($upgrade)) {
+
+                try {
+                    $success = $upgrade($DB);
+
+                    $result = ($result and $success);
+                } catch (Exception $e) {
+                    $result = false;
+                }
+
+                upgrade_plugin_savepoint($result, $upgrade->version, 'gradereport', 'grader');
+            }
+        }
+
+        return $result;
+    }
+}
diff --git a/grade/report/grader/version.php b/grade/report/grader/version.php
index 14c2e50..bf50771 100644
--- a/grade/report/grader/version.php
+++ b/grade/report/grader/version.php
@@ -25,6 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2011112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2011120801;
 $plugin->requires  = 2011112900;        // Requires this Moodle version
 $plugin->component = 'gradereport_grader'; // Full name of the plugin (used for diagnostics)
+
-- 
1.7.1


From 8a969fae6256eb050c9ba3458cb96b4995fc3b81 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Tue, 13 Dec 2011 13:15:49 -0600
Subject: Fixed SQL problem on postgreSQL databases.

---
 grade/report/grader/db/upgrade.php |   17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/grade/report/grader/db/upgrade.php b/grade/report/grader/db/upgrade.php
index 9cdbb4f..c4af5cd 100644
--- a/grade/report/grader/db/upgrade.php
+++ b/grade/report/grader/db/upgrade.php
@@ -23,11 +23,20 @@ class grader_manual_items extends gradereport_grader_upgrade_state {
     var $version = 2011120801;
 
     function upgrade($db) {
-        $sql = "UPDATE {grade_grades} gr, {grade_items} gi
-            SET gr.rawgrade = gr.finalgrade
-            WHERE gi.id = gr.itemid AND gi.itemtype = 'manual'";
+        $base_sql = "%s {grade_grades} gr, {grade_items} gi %s " .
+            "WHERE gi.id = gr.itemid AND gi.itemtype = 'manual'";
 
-        return $db->execute($sql);
+        $sql = sprintf($base_sql, "SELECT COUNT(*) FROM", "");
+
+        $count = $db->count_records_sql($sql);
+
+        if (empty($count)) {
+            return true;
+        } else {
+            $sql = sprintf($base_sql, "UPDATE", "SET gr.rawgrade = gr.finalgrade");
+
+            return $db->execute($sql);
+        }
     }
 }
 
-- 
1.7.1


From bcb5ad1d4e4eb0b1397fe84986f899e3dc14bb81 Mon Sep 17 00:00:00 2001
From: Robert Russo <rrusso@lsu.edu>
Date: Mon, 19 Dec 2011 10:08:20 -0600
Subject: Added hiding of minimum grades feature.

---
 admin/settings/grades.php     |    2 ++
 grade/edit/tree/item_form.php |    9 ++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index 0d42537..75dcf01 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -153,6 +153,8 @@ if (has_capability('moodle/grade:manage', $systemcontext)
                                                              'locktime' => get_string('locktime', 'grades'),
                                                              'aggregationcoef' => get_string('aggregationcoef', 'grades'),
                                                              'parentcategory' => get_string('parentcategory', 'grades'))));
+
+        $temp->add(new admin_setting_configcheckbox('grade_min_hide', get_string('minimum_hide', 'grades'), get_string('minimum_hide_help', 'grades'), '1'));
     }
     $ADMIN->add('grades', $temp);
 
diff --git a/grade/edit/tree/item_form.php b/grade/edit/tree/item_form.php
index 642be6b..c6d3ad3 100644
--- a/grade/edit/tree/item_form.php
+++ b/grade/edit/tree/item_form.php
@@ -79,9 +79,12 @@ class edit_item_form extends moodleform {
         $mform->addHelpButton('grademax', 'grademax', 'grades');
         $mform->disabledIf('grademax', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
 
-        $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
-        $mform->addHelpButton('grademin', 'grademin', 'grades');
-        $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
+        $grademin_hider = get_config('moodle', 'grade_min_hide');
+        if (empty($grademin_hider)) {
+            $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
+            $mform->addHelpButton('grademin', 'grademin', 'grades');
+            $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
+        }
 
         $mform->addElement('text', 'gradepass', get_string('gradepass', 'grades'));
         $mform->addHelpButton('gradepass', 'gradepass', 'grades');
-- 
1.7.1


From d5a01cdf575f2bf2c10a22750e95c2348adb405b Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 19 Dec 2011 10:40:01 -0600
Subject: Matching Moodle defaults

---
 admin/settings/grades.php |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index 75dcf01..269991a 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -154,7 +154,7 @@ if (has_capability('moodle/grade:manage', $systemcontext)
                                                              'aggregationcoef' => get_string('aggregationcoef', 'grades'),
                                                              'parentcategory' => get_string('parentcategory', 'grades'))));
 
-        $temp->add(new admin_setting_configcheckbox('grade_min_hide', get_string('minimum_hide', 'grades'), get_string('minimum_hide_help', 'grades'), '1'));
+        $temp->add(new admin_setting_configcheckbox('grade_min_hide', get_string('minimum_hide', 'grades'), get_string('minimum_hide_help', 'grades'), 0));
     }
     $ADMIN->add('grades', $temp);
 
-- 
1.7.1


From aa073fa8da2205bf9505d278b432f4c227bef6e4 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 19 Dec 2011 10:40:19 -0600
Subject: Changed definition after data instead of definition

---
 grade/edit/tree/item_form.php |   15 +++++++++------
 1 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/grade/edit/tree/item_form.php b/grade/edit/tree/item_form.php
index c6d3ad3..8d91e59 100644
--- a/grade/edit/tree/item_form.php
+++ b/grade/edit/tree/item_form.php
@@ -79,12 +79,9 @@ class edit_item_form extends moodleform {
         $mform->addHelpButton('grademax', 'grademax', 'grades');
         $mform->disabledIf('grademax', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
 
-        $grademin_hider = get_config('moodle', 'grade_min_hide');
-        if (empty($grademin_hider)) {
-            $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
-            $mform->addHelpButton('grademin', 'grademin', 'grades');
-            $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
-        }
+        $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
+        $mform->addHelpButton('grademin', 'grademin', 'grades');
+        $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
 
         $mform->addElement('text', 'gradepass', get_string('gradepass', 'grades'));
         $mform->addHelpButton('gradepass', 'gradepass', 'grades');
@@ -295,6 +292,12 @@ class edit_item_form extends moodleform {
         if (!$mform->elementExists('aggregationcoef') and !$mform->elementExists('parentcategory')) {
             $mform->removeElement('headerparent');
         }
+
+        // Freeze grademin element if option unavailable
+        $min_is_hidden = (bool) get_config('moodle', 'grade_min_hide');
+        if ($min_is_hidden and $mform->elementExists('grademin')) {
+            $mform->hardFreeze('grademin');
+        }
     }
 
 
-- 
1.7.1


From 641fa9ef39443354419bbed79912f5afbdd0f580 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 19 Dec 2011 10:46:17 -0600
Subject: Grademin agg checks (forces zero when applicable)

---
 lib/grade/grade_category.php |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index abe6120..20b01ff 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -571,6 +571,9 @@ class grade_category extends grade_object {
             return;
         }
 
+        // Used in grade minimizing
+        $min_is_hidden = (bool) get_config('moodle', 'grade_min_hide');
+
         // normalize the grades first - all will have value 0...1
         // ungraded items are not used in aggregation
         foreach ($grade_values as $itemid=>$v) {
@@ -584,6 +587,12 @@ class grade_category extends grade_object {
                 unset($grade_values[$itemid]);
                 continue;
             }
+
+            // Force grademin if not applicable
+            if ($min_is_hidden and $items[$itemid]->gradetype != GRADE_TYPE_SCALE) {
+                $items[$itemid]->grademin = 0;
+            }
+
             $grade_values[$itemid] = grade_grade::standardise_score($v, $items[$itemid]->grademin, $items[$itemid]->grademax, 0, 1);
         }
 
@@ -616,6 +625,10 @@ class grade_category extends grade_object {
         // do the maths
         $agg_grade = $this->aggregate_values($grade_values, $items);
 
+        if ($min_is_hidden and $this->grade_item->gradetype != GRADE_TYPE_SCALE) {
+            $this->grade_item->grademin = 0;
+        }
+
         // recalculate the grade back to requested range
         $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $this->grade_item->grademin, $this->grade_item->grademax);
 
-- 
1.7.1


From 1d1eb11f4b81a4ceeced7aea1601a3bb62b6db49 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Tue, 20 Dec 2011 09:39:59 -0600
Subject: Moved lang keys in alphabetical order

---
 lang/en/grades.php |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/lang/en/grades.php b/lang/en/grades.php
index b583eff..ebf6029 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -394,6 +394,8 @@ $string['meanselection'] = 'Grades selected for column averages';
 $string['meanselection_help'] = 'This setting determines whether cells with no grade should be included when calculating the average (mean) for each category or grade item.';
 $string['median'] = 'Median';
 $string['min'] = 'Lowest';
+$string['minimum_hide'] = 'Hide ' . $string['grademin'] . '.';
+$string['minimum_hide_help'] = 'By default, ' . $string['grademin'] . ' is used in calculating grades and weights. By hiding this feature, ' . $string['grademin'] . ' will be zero in all value grading scenarios.';
 $string['missingscale'] = 'Scale must be selected';
 $string['mode'] = 'Mode';
 $string['morethanmax'] = 'The grade entered for {$a->itemname} for {$a->username} is more than the maximum allowed';
-- 
1.7.1


From 02091dfe86fd15224269650a81f7887c195a7235 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Thu, 26 Jan 2012 15:14:22 -0600
Subject: Changes to the keep highest field (dropdowns)

---
 grade/edit/tree/category_form.php |    8 +++++++-
 grade/edit/tree/lib.php           |    8 +++++++-
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/grade/edit/tree/category_form.php b/grade/edit/tree/category_form.php
index aec1dea..06cbb6e 100644
--- a/grade/edit/tree/category_form.php
+++ b/grade/edit/tree/category_form.php
@@ -84,7 +84,13 @@ class edit_category_form extends moodleform {
             $options[$i] = $i;
         }
 
-        $mform->addElement('select', 'keephigh', get_string('keephigh', 'grades'), $options);
+        $options_h = array(0 => get_string('all'));
+
+        for ($i=1; $i<=20; $i++) {
+            $options_h[$i] = $i;
+        }
+
+        $mform->addElement('select', 'keephigh', get_string('keephigh', 'grades'), $options_h);
         $mform->addHelpButton('keephigh', 'keephigh', 'grades');
         if ((int)$CFG->grade_keephigh_flag & 2) {
             $mform->setAdvanced('keephigh');
diff --git a/grade/edit/tree/lib.php b/grade/edit/tree/lib.php
index 49af487..baa9871 100644
--- a/grade/edit/tree/lib.php
+++ b/grade/edit/tree/lib.php
@@ -989,7 +989,13 @@ class grade_edit_tree_column_keephigh extends grade_edit_tree_column_category {
     }
 
     public function get_category_cell($category, $levelclass, $params) {
-        $keephigh = '<input type="text" size="3" id="keephigh_'.$category->id.'" name="keephigh_'.$category->id.'" value="'.$category->keephigh.'" />';
+        $options_h = array(0 => get_string('all'));
+
+        for ($i=1; $i<=20; $i++) {
+            $options_h[$i] = $i;
+        }
+
+        $keephigh = html_writer::select($options_h, 'keephigh_'.$category->id, $category->keephigh, null);
 
         if ($this->forced) {
             $keephigh = $category->keephigh;
-- 
1.7.1


From 66b52def29700f8b324a5524c7a66865516efa6a Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 30 Jan 2012 11:56:06 -0600
Subject: Applied dropdown to droplow as well.

---
 grade/edit/tree/lib.php |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/grade/edit/tree/lib.php b/grade/edit/tree/lib.php
index baa9871..5112076 100644
--- a/grade/edit/tree/lib.php
+++ b/grade/edit/tree/lib.php
@@ -956,7 +956,13 @@ class grade_edit_tree_column_droplow extends grade_edit_tree_column_category {
     }
 
     public function get_category_cell($category, $levelclass, $params) {
-        $droplow = '<input type="text" size="3" id="droplow_'.$category->id.'" name="droplow_'.$category->id.'" value="'.$category->droplow.'" />';
+        $options = array(0 => get_string('none'));
+
+        for ($i=1; $i<=20; $i++) {
+            $options[$i] = $i;
+        }
+
+        $droplow = html_writer::select($options, 'droplow_'.$category->id, $category->droplow, null);
 
         if ($this->forced) {
             $droplow = $category->droplow;
-- 
1.7.1


From 4335b788bcba2ae9d4e0c66a186fe2b45c8696a1 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 30 Jan 2012 15:30:08 -0600
Subject: Preliminary work on letters

---
 grade/edit/letter/edit_form.php |    4 ++--
 grade/edit/letter/index.php     |   12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/grade/edit/letter/edit_form.php b/grade/edit/letter/edit_form.php
index 9931484..35ecd85 100644
--- a/grade/edit/letter/edit_form.php
+++ b/grade/edit/letter/edit_form.php
@@ -59,12 +59,12 @@ class edit_letter_form extends moodleform {
                 $mform->disabledIf($gradelettername, $gradeboundaryname, 'eq', -1);
             }
 
-            $mform->addElement('select', $gradeboundaryname, $gradeboundary." $i", $percentages);
+            $mform->addElement('text', $gradeboundaryname, $gradeboundary." $i");
             if ($i == 1) {
                 $mform->addHelpButton($gradeboundaryname, 'gradeboundary', 'grades');
             }
             $mform->setDefault($gradeboundaryname, -1);
-            $mform->setType($gradeboundaryname, PARAM_INT);
+            $mform->setType($gradeboundaryname, PARAM_FLOAT);
 
             if (!$admin) {
                 $mform->disabledIf($gradeboundaryname, 'override', 'notchecked');
diff --git a/grade/edit/letter/index.php b/grade/edit/letter/index.php
index e0a2904..be6e307 100644
--- a/grade/edit/letter/index.php
+++ b/grade/edit/letter/index.php
@@ -85,11 +85,11 @@ if (!$edit) {
     $max = 100;
     foreach($letters as $boundary=>$letter) {
         $line = array();
-        $line[] = format_float($max,2).' %';
-        $line[] = format_float($boundary,2).' %';
+        $line[] = format_float($max,5).' %';
+        $line[] = format_float($boundary,5).' %';
         $line[] = format_string($letter);
         $data[] = $line;
-        $max = $boundary - 0.01;
+        $max = $boundary - 0.00001;
     }
 
     print_grade_page_head($COURSE->id, 'letter', 'view', get_string('gradeletters', 'grades'));
@@ -100,9 +100,9 @@ if (!$edit) {
 
     $table = new html_table();
     $table->head  = array(get_string('max', 'grades'), get_string('min', 'grades'), get_string('letter', 'grades'));
-    $table->size  = array('30%', '30%', '40%');
+    $table->size  = array('33%', '33%', '34%');
     $table->align = array('left', 'left', 'left');
-    $table->width = '30%';
+    $table->width = '40%';
     $table->data  = $data;
     $table->tablealign  = 'center';
     echo html_writer::table($table);
@@ -147,7 +147,7 @@ if (!$edit) {
                 if ($letter == '') {
                     continue;
                 }
-                $letters[$data->$gradeboundaryname] = $letter;
+                $letters["{$data->$gradeboundaryname}"] = $letter;
             }
         }
         krsort($letters, SORT_NUMERIC);
-- 
1.7.1


From 35bde25f9f898defe9d7b50509038b908080a90e Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 1 Feb 2012 14:15:57 -0600
Subject: Letter Admin options

---
 admin/settings/grades.php |   18 +++++++++++++++++-
 lang/en/grades.php        |    4 ++++
 2 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index 0d42537..f507268 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -165,9 +165,25 @@ if (has_capability('moodle/grade:manage', $systemcontext)
         $outcomes = new admin_externalpage('outcomes', get_string('outcomes', 'grades'), $CFG->wwwroot.'/grade/edit/outcome/index.php', 'moodle/grade:manage');
         $ADMIN->add('grades', $outcomes);
     }
-    $letters = new admin_externalpage('letters', get_string('letters', 'grades'), $CFG->wwwroot.'/grade/edit/letter/index.php', 'moodle/grade:manageletters');
+
+    $letters_str = get_string('letters', 'grades');
+    $letters_base = $CFG->wwwroot.'/grade/edit/letter';
+    $letters = new admin_externalpage('letters', $letters_str, $letters_base . '/index.php', 'moodle/grade:manageletters');
     $ADMIN->add('grades', $letters);
 
+    $letters_settings_str = get_string('letter', 'grades') . ' ' . get_string('edit') . ' ' . get_string('settings');
+    $temp = new admin_settingpage('letterssettings', $letters_settings_str, 'moodle/grade:manageletters');
+    if ($ADMIN->fulltree) {
+        $temp->add(new admin_setting_configcheckbox('grade_letters_custom',
+            get_String('letterscustompercents', 'grades'), get_string('letterscustompercents_help', 'grades'), 0));
+
+        $decimals = range(0, 5);
+
+        $temp->add(new admin_setting_configselect('grade_letters_decimals',
+            get_string('lettersdecimals', 'grades'), get_string('lettersdecimals_help', 'grades'), 3, $decimals));
+    }
+    $ADMIN->add('grades', $temp);
+
     // The plugins must implement a settings.php file that adds their admin settings to the $settings object
 
     // Reports
diff --git a/lang/en/grades.php b/lang/en/grades.php
index b583eff..edb2133 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -371,6 +371,10 @@ $string['lettergradenonnumber'] = 'Low and/or High grade were non-numeric for';
 $string['letterpercentage'] = 'Letter (percentage)';
 $string['letterreal'] = 'Letter (real)';
 $string['letters'] = 'Letters';
+$string['letterscustompercents'] = 'Custom Percentages';
+$string['letterscustompercents_help'] = 'Allows for users to enter a value for the percents.';
+$string['lettersdecimals'] = 'Decimal Rounding';
+$string['lettersdecimals_help'] = 'If using _' . $string['letterscustompercents'] . '_, then round to this decimal.';
 $string['linkedactivity'] = 'Linked activity';
 $string['linkedactivity_help'] = 'This setting specifies an activity to which this outcome item is linked. This may be used to measure student performance on criteria not assessed by the activity grade.';
 $string['linktoactivity'] = 'Link to {$a->name} activity';
-- 
1.7.1


From 8ea6658367480813b1d59a0850bc81cc3886c4ff Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 1 Feb 2012 14:54:36 -0600
Subject: Use admin letter options.

---
 grade/edit/letter/edit_form.php |   24 ++++++++++++++++++++----
 grade/edit/letter/index.php     |   15 +++++++++------
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/grade/edit/letter/edit_form.php b/grade/edit/letter/edit_form.php
index 35ecd85..4854f4a 100644
--- a/grade/edit/letter/edit_form.php
+++ b/grade/edit/letter/edit_form.php
@@ -39,11 +39,15 @@ class edit_letter_form extends moodleform {
         $gradeletter       = get_string('gradeletter', 'grades');
         $gradeboundary     = get_string('gradeboundary', 'grades');
 
-        $percentages = array(-1 => get_string('unused', 'grades'));
+        $unused_str = get_string('unused', 'grades');
+
+        $percentages = array(-1 => $unused_str);
         for ($i=100; $i > -1; $i--) {
             $percentages[$i] = "$i %";
         }
 
+        $custom = get_config('moodle', 'grade_letters_custom');
+
         for($i=1; $i<$num+1; $i++) {
             $gradelettername = 'gradeletter'.$i;
             $gradeboundaryname = 'gradeboundary'.$i;
@@ -56,15 +60,27 @@ class edit_letter_form extends moodleform {
 
             if (!$admin) {
                 $mform->disabledIf($gradelettername, 'override', 'notchecked');
+
                 $mform->disabledIf($gradelettername, $gradeboundaryname, 'eq', -1);
             }
 
-            $mform->addElement('text', $gradeboundaryname, $gradeboundary." $i");
+            if ($custom) {
+                $mform->addElement('text', $gradeboundaryname, $gradeboundary." $i");
+
+                $mform->addRule($gradeboundaryname, null, 'numeric', '', 'client');
+
+                $mform->setType($gradeboundaryname, PARAM_FLOAT);
+            } else {
+                $mform->addElement('select', $gradeboundaryname, $gradeboundary." $i", $percentages);
+
+                $mform->setType($gradeboundaryname, PARAM_INT);
+            }
+
+            $mform->setDefault($gradeboundaryname, -1);
+
             if ($i == 1) {
                 $mform->addHelpButton($gradeboundaryname, 'gradeboundary', 'grades');
             }
-            $mform->setDefault($gradeboundaryname, -1);
-            $mform->setType($gradeboundaryname, PARAM_FLOAT);
 
             if (!$admin) {
                 $mform->disabledIf($gradeboundaryname, 'override', 'notchecked');
diff --git a/grade/edit/letter/index.php b/grade/edit/letter/index.php
index be6e307..351e87d 100644
--- a/grade/edit/letter/index.php
+++ b/grade/edit/letter/index.php
@@ -77,19 +77,21 @@ $pagename  = get_string('letters', 'grades');
 $letters = grade_get_letters($context);
 $num = count($letters) + 3;
 
+$custom = (bool) get_config('moodle', 'grade_letters_custom');
+$decimals = $custom ? (int) get_config('moodle', 'grade_letters_decimals') : 2;
+
 //if were viewing the letters
 if (!$edit) {
 
     $data = array();
-
     $max = 100;
     foreach($letters as $boundary=>$letter) {
         $line = array();
-        $line[] = format_float($max,5).' %';
-        $line[] = format_float($boundary,5).' %';
+        $line[] = format_float($max, $decimals).' %';
+        $line[] = format_float($boundary, $decimals).' %';
         $line[] = format_string($letter);
         $data[] = $line;
-        $max = $boundary - 0.00001;
+        $max = $boundary - (1 / pow(10, $decimals));
     }
 
     print_grade_page_head($COURSE->id, 'letter', 'view', get_string('gradeletters', 'grades'));
@@ -120,7 +122,7 @@ if (!$edit) {
         $gradeboundaryname = 'gradeboundary'.$i;
 
         $data->$gradelettername   = $letter;
-        $data->$gradeboundaryname = $boundary;
+        $data->$gradeboundaryname = $custom ? format_float($boundary, $decimals) : (int) $boundary;
         $i++;
     }
     $data->override = $DB->record_exists('grade_letters', array('contextid' => $context->id));
@@ -147,7 +149,8 @@ if (!$edit) {
                 if ($letter == '') {
                     continue;
                 }
-                $letters["{$data->$gradeboundaryname}"] = $letter;
+                $stored = $custom ? "{$data->$gradeboundaryname}" : $data->$gradeboundaryname;
+                $letters[$stored] = $letter;
             }
         }
         krsort($letters, SORT_NUMERIC);
-- 
1.7.1


From 6c5ae9493bbf8b954e0e3091135c138900eca42a Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 1 Feb 2012 14:56:28 -0600
Subject: Made rounding default to original default

---
 admin/settings/grades.php |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index f507268..e9962c2 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -180,7 +180,7 @@ if (has_capability('moodle/grade:manage', $systemcontext)
         $decimals = range(0, 5);
 
         $temp->add(new admin_setting_configselect('grade_letters_decimals',
-            get_string('lettersdecimals', 'grades'), get_string('lettersdecimals_help', 'grades'), 3, $decimals));
+            get_string('lettersdecimals', 'grades'), get_string('lettersdecimals_help', 'grades'), 2, $decimals));
     }
     $ADMIN->add('grades', $temp);
 
-- 
1.7.1


From 1fbc4bbcadb542f8631b77fa692ef46a65dce051 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 1 Feb 2012 15:10:19 -0600
Subject: Decimal place piggyback off item setting

---
 admin/settings/grades.php   |    5 -----
 grade/edit/letter/index.php |   12 +++++++++---
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index e9962c2..547137c 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -176,11 +176,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
     if ($ADMIN->fulltree) {
         $temp->add(new admin_setting_configcheckbox('grade_letters_custom',
             get_String('letterscustompercents', 'grades'), get_string('letterscustompercents_help', 'grades'), 0));
-
-        $decimals = range(0, 5);
-
-        $temp->add(new admin_setting_configselect('grade_letters_decimals',
-            get_string('lettersdecimals', 'grades'), get_string('lettersdecimals_help', 'grades'), 2, $decimals));
     }
     $ADMIN->add('grades', $temp);
 
diff --git a/grade/edit/letter/index.php b/grade/edit/letter/index.php
index 351e87d..0daac69 100644
--- a/grade/edit/letter/index.php
+++ b/grade/edit/letter/index.php
@@ -45,6 +45,9 @@ if (!$edit) {
     require_capability('moodle/grade:manageletters', $context);
 }
 
+$custom = (bool) get_config('moodle', 'grade_letters_custom');
+$decimals = $custom ? (int) get_config('moodle', 'grade_decimalpoints') : 2;
+
 $returnurl = null;
 $editparam = null;
 if ($context->contextlevel == CONTEXT_SYSTEM or $context->contextlevel == CONTEXT_COURSECAT) {
@@ -66,6 +69,12 @@ if ($context->contextlevel == CONTEXT_SYSTEM or $context->contextlevel == CONTEX
     $returnurl = $CFG->wwwroot.'/grade/edit/letter/index.php?id='.$context->id;
     $editparam = '&edit=1';
 
+    if ($custom) {
+        $item = grade_item::fetch(array('itemtype' => 'course', 'courseid' => $course->id));
+
+        $decimals = $item ? $item->get_decimals() : $decimals;
+    }
+
     $gpr = new grade_plugin_return(array('type'=>'edit', 'plugin'=>'letter', 'courseid'=>$course->id));
 } else {
     print_error('invalidcourselevel');
@@ -77,9 +86,6 @@ $pagename  = get_string('letters', 'grades');
 $letters = grade_get_letters($context);
 $num = count($letters) + 3;
 
-$custom = (bool) get_config('moodle', 'grade_letters_custom');
-$decimals = $custom ? (int) get_config('moodle', 'grade_letters_decimals') : 2;
-
 //if were viewing the letters
 if (!$edit) {
 
-- 
1.7.1


From 10d9fe6acf572602b41493fbfe74e6178dc9a320 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Thu, 2 Feb 2012 13:09:12 -0600
Subject: Adds admin defined strict letter names

---
 admin/settings/grades.php       |   16 +++++++++++++++-
 grade/edit/letter/edit_form.php |   21 ++++++++++++++++++++-
 lang/en/grades.php              |    7 +++++--
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index 547137c..48502fc 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -175,7 +175,21 @@ if (has_capability('moodle/grade:manage', $systemcontext)
     $temp = new admin_settingpage('letterssettings', $letters_settings_str, 'moodle/grade:manageletters');
     if ($ADMIN->fulltree) {
         $temp->add(new admin_setting_configcheckbox('grade_letters_custom',
-            get_String('letterscustompercents', 'grades'), get_string('letterscustompercents_help', 'grades'), 0));
+            get_string('letterscustompercents', 'grades'), get_string('letterscustompercents_help', 'grades'), 0));
+
+
+        $temp->add(new admin_setting_configcheckbox('grade_letters_strict',
+            get_string('lettersstrictletter', 'grades'), get_string('lettersstrictletter_help', 'grades'), 0));
+
+        $params = array('courseid' => 0);
+
+        $db_scales = $DB->get_records_menu('scale', $params, '', 'id, name');
+
+        $scales = array(0 => get_string('lettersdefaultletters', 'grades')) + $db_scales;
+
+        $temp->add(new admin_setting_configselect('grade_letters_names',
+            get_string('lettersnames', 'grades'),
+            get_string('lettersname_help', 'grades'), 0, $scales));
     }
     $ADMIN->add('grades', $temp);
 
diff --git a/grade/edit/letter/edit_form.php b/grade/edit/letter/edit_form.php
index 4854f4a..106a3f4 100644
--- a/grade/edit/letter/edit_form.php
+++ b/grade/edit/letter/edit_form.php
@@ -24,6 +24,8 @@ require_once $CFG->libdir.'/formslib.php';
 class edit_letter_form extends moodleform {
 
     public function definition() {
+        global $DB;
+
         $mform =& $this->_form;
         $num   = $this->_customdata['num'];
         $admin = $this->_customdata['admin'];
@@ -47,12 +49,29 @@ class edit_letter_form extends moodleform {
         }
 
         $custom = get_config('moodle', 'grade_letters_custom');
+        $strict = get_config('moodle', 'grade_letters_strict');
+
+        $default = get_config('moodle', 'grade_letters_names');
+
+        if ($default and $scale = $DB->get_record('scale', array('id' => $default))) {
+            $default_letters = $scale->scale;
+        } else {
+            $default_letters = get_string('lettersdefaultletters', 'grades');
+        }
+
+        $default_letters = array_reverse(explode(',', $default_letters));
+        $letters = array_combine($default_letters, $default_letters);
 
         for($i=1; $i<$num+1; $i++) {
             $gradelettername = 'gradeletter'.$i;
             $gradeboundaryname = 'gradeboundary'.$i;
 
-            $mform->addElement('text', $gradelettername, $gradeletter." $i");
+            if ($strict) {
+                $mform->addElement('select', $gradelettername, $gradeletter." $i", $letters);
+            } else {
+                $mform->addElement('text', $gradelettername, $gradeletter." $i");
+            }
+
             if ($i == 1) {
                 $mform->addHelpButton($gradelettername, 'gradeletter', 'grades');
             }
diff --git a/lang/en/grades.php b/lang/en/grades.php
index edb2133..86f4193 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -373,8 +373,11 @@ $string['letterreal'] = 'Letter (real)';
 $string['letters'] = 'Letters';
 $string['letterscustompercents'] = 'Custom Percentages';
 $string['letterscustompercents_help'] = 'Allows for users to enter a value for the percents.';
-$string['lettersdecimals'] = 'Decimal Rounding';
-$string['lettersdecimals_help'] = 'If using _' . $string['letterscustompercents'] . '_, then round to this decimal.';
+$string['lettersdefaultletters'] = 'F,D,C,B,A';
+$string['lettersstrictletter'] = 'Strict Letter names';
+$string['lettersstrictletter_help'] = 'This setting forces the default letter names defined with the selected Letter names.';
+$string['lettersnames'] = 'Letter names';
+$string['lettersname_help'] = 'This setting forces the default letter names defined with this system scale. __Note__: The default letter names are A-F.';
 $string['linkedactivity'] = 'Linked activity';
 $string['linkedactivity_help'] = 'This setting specifies an activity to which this outcome item is linked. This may be used to measure student performance on criteria not assessed by the activity grade.';
 $string['linktoactivity'] = 'Link to {$a->name} activity';
-- 
1.7.1


From 0be49b12c6253f9a2a574893363e7ad5634396f0 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 13 Feb 2012 14:12:21 -0600
Subject: Curve-to system wide setting

---
 admin/settings/grades.php     |    4 ++++
 grade/edit/tree/index.php     |    7 +++++++
 grade/edit/tree/item.php      |   23 ++++++++++++++++++++++-
 grade/edit/tree/item_form.php |   22 ++++++++++++++++++++--
 grade/edit/tree/lib.php       |   20 ++++++++++++++++++--
 lang/en/grades.php            |    4 ++++
 6 files changed, 75 insertions(+), 5 deletions(-)

diff --git a/admin/settings/grades.php b/admin/settings/grades.php
index 0d42537..8fe5ebf 100644
--- a/admin/settings/grades.php
+++ b/admin/settings/grades.php
@@ -122,6 +122,10 @@ if (has_capability('moodle/grade:manage', $systemcontext)
     /// Grade item settings
     $temp = new admin_settingpage('gradeitemsettings', get_string('gradeitemsettings', 'grades'), 'moodle/grade:manage');
     if ($ADMIN->fulltree) {
+        $temp->add(new admin_setting_configcheckbox('grade_multfactor_alt',
+            get_string('multfactor_alt', 'grades'),
+            get_string('multfactor_alt_desc', 'grades'), 0));
+
         $temp->add(new admin_setting_configselect('grade_displaytype', get_string('gradedisplaytype', 'grades'),
                                                   get_string('gradedisplaytype_help', 'grades'), GRADE_DISPLAY_TYPE_REAL, $display_types));
 
diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php
index 8d88615..4b39d25 100644
--- a/grade/edit/tree/index.php
+++ b/grade/edit/tree/index.php
@@ -234,6 +234,8 @@ if ($current_view != '') {
 //Ideally we could do the updates through $grade_edit_tree to avoid recreating it
 $recreatetree = false;
 
+$curve_to = get_config('moodle', 'grade_multfactor_alt');
+
 if ($data = data_submitted() and confirm_sesskey()) {
     // Perform bulk actions first
     if (!empty($data->bulkmove)) {
@@ -277,10 +279,15 @@ if ($data = data_submitted() and confirm_sesskey()) {
 
             $grade_item = grade_item::fetch(array('id'=>$aid, 'courseid'=>$courseid));
 
+            if ($param === 'multfactor' and $curve_to) {
+                $value = $value / $grade_item->grademax;
+            }
+
             if ($param === 'grademax' and $value < $grade_item->grademin) {
                 // better not allow values lower than grade min
                 $value = $grade_item->grademin;
             }
+
             $grade_item->$param = $value;
 
             $grade_item->update();
diff --git a/grade/edit/tree/item.php b/grade/edit/tree/item.php
index 1ce936c..6fad7c5 100644
--- a/grade/edit/tree/item.php
+++ b/grade/edit/tree/item.php
@@ -44,6 +44,8 @@ $returnurl = $gpr->get_return_url('index.php?id='.$course->id);
 
 $heading = get_string('itemsedit', 'grades');
 
+$curve_to = get_config('moodle', 'grade_multfactor_alt');
+
 if ($grade_item = grade_item::fetch(array('id'=>$id, 'courseid'=>$courseid))) {
     // redirect if outcomeid present
     if (!empty($grade_item->outcomeid) && !empty($CFG->enableoutcomes)) {
@@ -78,10 +80,18 @@ if ($item->hidden > 1) {
 
 $item->locked = !empty($item->locked);
 
+$multfactor = $item->multfactor;
+$curve_decimals = 4;
+
+if ($curve_to) {
+    $curve_decimals = $decimalpoints;
+    $multfactor *= $item->grademax;
+}
+
 $item->grademax        = format_float($item->grademax, $decimalpoints);
 $item->grademin        = format_float($item->grademin, $decimalpoints);
 $item->gradepass       = format_float($item->gradepass, $decimalpoints);
-$item->multfactor      = format_float($item->multfactor, 4);
+$item->multfactor      = format_float($multfactor, $curve_decimals);
 $item->plusfactor      = format_float($item->plusfactor, 4);
 
 if ($parent_category->aggregation == GRADE_AGGREGATE_SUM or $parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN2) {
@@ -130,6 +140,17 @@ if ($mform->is_cancelled()) {
         }
     }
 
+    // Special handling of curve to
+    if ($curve_to) {
+        if (empty($data->multfactor) || $data->multfactor <= 0.0000) {
+            $data->multfactor = 1.0000;
+        } else if (!isset($data->curve_to) and isset($item->multfactor)) {
+            $data->multfactor = $grade_item->multfactor;
+        } else {
+            $data->multfactor = $data->multfactor / $data->grademax;
+        }
+    }
+
     $grade_item = new grade_item(array('id'=>$id, 'courseid'=>$courseid));
     grade_item::set_properties($grade_item, $data);
     $grade_item->outcomeid = null;
diff --git a/grade/edit/tree/item_form.php b/grade/edit/tree/item_form.php
index 642be6b..e16fa42 100644
--- a/grade/edit/tree/item_form.php
+++ b/grade/edit/tree/item_form.php
@@ -88,8 +88,26 @@ class edit_item_form extends moodleform {
         $mform->disabledIf('gradepass', 'gradetype', 'eq', GRADE_TYPE_NONE);
         $mform->disabledIf('gradepass', 'gradetype', 'eq', GRADE_TYPE_TEXT);
 
-        $mform->addElement('text', 'multfactor', get_string('multfactor', 'grades'));
-        $mform->addHelpButton('multfactor', 'multfactor', 'grades');
+        if (get_config('moodle', 'grade_multfactor_alt')) {
+            $curve_to = get_string('multfactor_alt', 'grades');
+            $perform_curve = get_string('allow_multfactor_alt', 'grades');
+
+            $mform->addElement('checkbox', 'curve_to', $perform_curve,'');
+
+            $mform->setAdvanced('curve_to');
+
+            $mform->addElement('text', 'multfactor', $curve_to);
+
+            $mform->disabledIf('curve_to', 'gradetype', 'eq', GRADE_TYPE_NONE);
+            $mform->disabledIf('curve_to', 'gradetype', 'eq', GRADE_TYPE_TEXT);
+
+            $mform->disabledIf('multfactor', 'curve_to', 'notchecked');
+            $mform->addHelpButton('multfactor', 'multfactor_alt', 'grades', null);
+        } else {
+            $mform->addElement('text', 'multfactor', get_string('multfactor', 'grades'));
+            $mform->addHelpButton('multfactor', 'multfactor', 'grades');
+        }
+
         $mform->setAdvanced('multfactor');
         $mform->disabledIf('multfactor', 'gradetype', 'eq', GRADE_TYPE_NONE);
         $mform->disabledIf('multfactor', 'gradetype', 'eq', GRADE_TYPE_TEXT);
diff --git a/grade/edit/tree/lib.php b/grade/edit/tree/lib.php
index 49af487..8d44a53 100644
--- a/grade/edit/tree/lib.php
+++ b/grade/edit/tree/lib.php
@@ -1009,15 +1009,20 @@ class grade_edit_tree_column_keephigh extends grade_edit_tree_column_category {
 }
 
 class grade_edit_tree_column_multfactor extends grade_edit_tree_column {
+    private $curve_to;
 
     public function __construct($params) {
+        $this->curve_to = get_config('moodle', 'grade_multfactor_alt');
         parent::__construct();
     }
 
     public function get_header_cell() {
         global $OUTPUT;
         $headercell = clone($this->headercell);
-        $headercell->text = get_string('multfactor', 'grades').$OUTPUT->help_icon('multfactor', 'grades');
+
+        $name = $this->curve_to ? 'multfactor_alt' : 'multfactor';
+
+        $headercell->text = get_string($name, 'grades').$OUTPUT->help_icon($name, 'grades');
         return $headercell;
     }
 
@@ -1037,7 +1042,18 @@ class grade_edit_tree_column_multfactor extends grade_edit_tree_column {
             return $itemcell;
         }
 
-        $multfactor = '<input type="text" size="4" id="multfactor'.$item->id.'" name="multfactor_'.$item->id.'" value="'.grade_edit_tree::format_number($item->multfactor).'" />';
+        $size = 4;
+        $multfactor = $item->multfactor;
+
+        if ($this->curve_to) {
+            $decimals = $item->get_decimals();
+            $size += $decimals;
+            $multfactor = format_float(($multfactor * $item->grademax), $decimals);
+        } else {
+            $multfactor = grade_edit_tree::format_number($multfactor);
+        }
+
+        $multfactor = '<input type="text" size="'.$size.'" id="multfactor'.$item->id.'" name="multfactor_'.$item->id.'" value="'.$multfactor.'" />';
 
         $itemcell->text = $multfactor;
         return $itemcell;
diff --git a/lang/en/grades.php b/lang/en/grades.php
index b583eff..3505c4d 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -401,6 +401,10 @@ $string['moveselectedto'] = 'Move selected items to';
 $string['movingelement'] = 'Moving {$a}';
 $string['multfactor'] = 'Multiplicator';
 $string['multfactor_help'] = 'The multiplicator is the factor by which all grades for this grade item will be multiplied, with a maximum value of the maximum grade. For example, if the multiplicator is 2 and the maximum grade is 100, then all grades less than 50 are multiplied by 2, and all grades 50 and above are changed to 100.';
+$string['allow_multfactor_alt'] = 'Perform Curve To';
+$string['multfactor_alt'] = 'Curve To';
+$string['multfactor_alt_desc'] = 'Curve To will replace the Multiplicator element on the grade item edit form. Users will instead enter a value to _Curve To_ and the Multiplicator is applied under the covers.';
+$string['multfactor_alt_help'] = 'The curve to is the value by which all the grades for this grade item will be adjusted. For example, if the curve-to is 200, and the maximum grade is 100, then all grades are adjusted by multiplying all the grades by 2.';
 $string['mypreferences'] = 'My preferences';
 $string['myreportpreferences'] = 'My report preferences';
 $string['navmethod'] = 'Navigation method';
-- 
1.7.1


From e2832d6152bd5140e1758473e5aa31e01946b9e0 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 13 Feb 2012 15:17:02 -0600
Subject: Weighted percents on common aggregations.

---
 grade/report/grader/lib.php |   54 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 53 insertions(+), 1 deletions(-)

diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index bcacf6d..6714bfb 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -93,6 +93,8 @@ class grade_report_grader extends grade_report {
      */
     protected $feedback_trunc_length = 50;
 
+    protected $weightedtotals = array();
+
     /**
      * Constructor. Sets local copies of user preferences and initialises grade_tree.
      * @param int $courseid
@@ -780,12 +782,14 @@ class grade_report_grader extends grade_report {
                     $itemcell = new html_table_cell();
                     $itemcell->attributes['class'] = $type . ' ' . $catlevel . 'highlightable';
 
+                    $percents = $this->get_weighted_percents($element['object']);
+
                     if ($element['object']->is_hidden()) {
                         $itemcell->attributes['class'] .= ' hidden';
                     }
 
                     $itemcell->colspan = $colspan;
-                    $itemcell->text = shorten_text($headerlink) . $arrow;
+                    $itemcell->text = shorten_text($headerlink) . $percents . $arrow;
                     $itemcell->header = true;
                     $itemcell->scope = 'col';
 
@@ -1641,5 +1645,53 @@ class grade_report_grader extends grade_report {
 
         return $arrows;
     }
+
+    public function get_weighted_percents($item) {
+        $parent = $item->get_parent_category();
+
+        if (!$parent or $item->is_course_item()) {
+            return '';
+        }
+
+        $determine_weight = function($item) use ($parent) {
+            switch ($parent->aggregation) {
+                case GRADE_AGGREGATE_WEIGHTED_MEAN:
+                    return $item->aggregationcoef;
+                case GRADE_AGGREGATE_WEIGHTED_MEAN2:
+                    return $item->grademax - $item->grademin;
+                case GRADE_AGGREGATE_SUM:
+                    return $item->grademax;
+                default: return false;
+            }
+        };
+
+        $evaluated = $determine_weight($item);
+
+        if (empty($evaluated)) {
+            return '';
+        }
+
+        if (!isset($this->weightedtotals[$parent->id])) {
+            $total_weight = 0;
+
+            $grade_items = $parent->get_children();
+            foreach ($grade_items as $gid => $grade_item) {
+                if ($grade_item['type'] == 'category') {
+                    $item = $grade_item['object']->get_grade_item();
+                } else {
+                    $item = $grade_item['object'];
+                }
+
+                $total_weight += $determine_weight($item);
+            }
+
+            $this->weightedtotals[$parent->id] = $total_weight;
+        }
+
+        $decimals = $parent->get_grade_item()->get_decimals();
+        $computed = $evaluated / $this->weightedtotals[$parent->id];
+
+        return ' (' . format_float($computed * 100, $decimals) . '%) ';
+    }
 }
 
-- 
1.7.1


From 57e218362352404344549daceaa38057ebb2cb13 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Thu, 2 Feb 2012 15:01:11 -0600
Subject: Quick Edit as a grade report

---
 grade/report/quick_edit/db/access.php              |   40 +++++++++
 grade/report/quick_edit/index.php                  |   85 ++++++++++++++++++++
 .../quick_edit/lang/en/gradereport_quick_edit.php  |   27 ++++++
 grade/report/quick_edit/lib.php                    |   46 +++++++++++
 grade/report/quick_edit/version.php                |   27 ++++++
 5 files changed, 225 insertions(+), 0 deletions(-)
 create mode 100755 grade/report/quick_edit/db/access.php
 create mode 100755 grade/report/quick_edit/index.php
 create mode 100755 grade/report/quick_edit/lang/en/gradereport_quick_edit.php
 create mode 100755 grade/report/quick_edit/lib.php
 create mode 100755 grade/report/quick_edit/version.php

diff --git a/grade/report/quick_edit/db/access.php b/grade/report/quick_edit/db/access.php
new file mode 100755
index 0000000..d8c4b35
--- /dev/null
+++ b/grade/report/quick_edit/db/access.php
@@ -0,0 +1,40 @@
+<?php  // $Id: access.php,v 1.5 2008-05-10 06:34:23 pcali1 Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.com       //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+
+$capabilities = array(
+
+    'gradereport/quick_edit:view' => array(
+        'riskbitmask' => RISK_PERSONAL,
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_COURSE,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW,
+        )
+    )
+);
+
+?>
diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
new file mode 100755
index 0000000..c943128
--- /dev/null
+++ b/grade/report/quick_edit/index.php
@@ -0,0 +1,85 @@
+<?php
+
+///////////////////////////////////////////////////////////////////////////
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.com       //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once '../../../config.php';
+require_once $CFG->dirroot.'/lib/gradelib.php';
+require_once $CFG->dirroot.'/grade/lib.php';
+require_once $CFG->dirroot.'/grade/report/quick_edit/lib.php';
+
+$courseid = required_param('id', PARAM_INT);
+$itemtype = optional_param('item', 'grade', PARAM_TEXT);
+$itemid = optional_param('itemid', 0, PARAM_INT);
+$groupid  = optional_param('group', null, PARAM_INT);
+
+$PAGE->set_url(new moodle_url('/grade/report/quick_edit/index.php', array(
+    'id' => $courseid,
+    'item' => $itemtype,
+    'itemid' => $itemid,
+    'group' => $groupid
+)));
+
+if (!$course = $DB->get_record('course', array('id' => $courseid))) {
+    print_error('nocourseid');
+}
+
+require_login($course);
+
+$context = get_context_instance(CONTEXT_COURSE, $course->id);
+
+// This is the normal requirements
+require_capability('gradereport/quick_edit:view', $context);
+require_capability('moodle/grade:viewall', $context);
+require_capability('moodle/grade:edit', $context);
+// End permission
+
+$_s = function($key, $a = null) {
+    return get_string($key, 'gradereport_quick_edit');
+};
+
+$gpr = new grade_plugin_return(array(
+    'type' => 'report', 'plugin' => 'quick_edit', 'courseid' => $courseid
+));
+
+if (!isset($USER->grade_last_report)) {
+    $USER->grade_last_report = array();
+}
+$USER->grade_last_report[$course->id] = 'quick_edit';
+
+grade_regrade_final_grades($courseid);
+
+$reportname = $_s('pluginname');
+
+$PAGE->set_context($context);
+
+print_grade_page_head($course->id, 'report', 'quick_edit', $reportname, false);
+
+$report = new grade_report_quick_edit(
+    $courseid, $gpr, $context, $itemtype, $itemid, $group
+);
+
+echo $report->output();
+
+echo $OUTPUT->footer();
+
+?>
diff --git a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
new file mode 100755
index 0000000..c000b2d
--- /dev/null
+++ b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
@@ -0,0 +1,27 @@
+<?php
+
+///////////////////////////////////////////////////////////////////////////
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.com       //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+// General Strings
+$string['pluginname'] = 'Quick Edit';
+$string['quick_edit:view'] = 'View the '.$string['pluginname'].' report';
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
new file mode 100755
index 0000000..8b05270
--- /dev/null
+++ b/grade/report/quick_edit/lib.php
@@ -0,0 +1,46 @@
+<?php
+
+///////////////////////////////////////////////////////////////////////////
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.com       //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once($CFG->dirroot . '/grade/report/lib.php');
+require_once($CFG->libdir.'/tablelib.php');
+
+class grade_report_quick_edit extends grade_report {
+
+    function process_data($data) {
+    }
+
+    function process_action($target, $action) {
+    }
+
+    function _s($key, $a = null) {
+        return get_string($key, 'gradereport_quick_edit', $a);
+    }
+
+    function __construct($courseid, $gpr, $context, $itemtype, $itemid, $groupid=null) {
+        parent::__construct($courseid, $gpr, $context);
+    }
+
+    function output() {
+    }
+}
diff --git a/grade/report/quick_edit/version.php b/grade/report/quick_edit/version.php
new file mode 100755
index 0000000..438ddd1
--- /dev/null
+++ b/grade/report/quick_edit/version.php
@@ -0,0 +1,27 @@
+<?php
+
+///////////////////////////////////////////////////////////////////////////
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.com       //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+$plugin->version  = 2012020214;
+$plugin->requires = 2010090501;
+
-- 
1.7.1


From abd289f87f0b77a0d73d7fbd9884d71de7ed19b5 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Thu, 2 Feb 2012 15:25:25 -0600
Subject: Scaffold quick edit screen, check for validity.

---
 grade/report/quick_edit/classes/lib.php            |    4 +++
 grade/report/quick_edit/index.php                  |    6 ++++-
 .../quick_edit/lang/en/gradereport_quick_edit.php  |    3 ++
 grade/report/quick_edit/lib.php                    |   21 ++++++++++++++++++++
 grade/report/quick_edit/screens/grade/lib.php      |    4 +++
 grade/report/quick_edit/screens/user/lib.php       |    4 +++
 6 files changed, 41 insertions(+), 1 deletions(-)
 create mode 100644 grade/report/quick_edit/classes/lib.php
 create mode 100644 grade/report/quick_edit/screens/grade/lib.php
 create mode 100644 grade/report/quick_edit/screens/user/lib.php

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
new file mode 100644
index 0000000..beaed35
--- /dev/null
+++ b/grade/report/quick_edit/classes/lib.php
@@ -0,0 +1,4 @@
+<?php
+
+abstract class quit_edit_screen {
+}
diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index c943128..47e73fe 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -43,6 +43,10 @@ if (!$course = $DB->get_record('course', array('id' => $courseid))) {
     print_error('nocourseid');
 }
 
+if (!in_array($itemtype, grade_report_quick_edit::valid_types())) {
+    print_error('notvalid', 'gradereport_quick_edit', '', $itemtype);
+}
+
 require_login($course);
 
 $context = get_context_instance(CONTEXT_COURSE, $course->id);
@@ -54,7 +58,7 @@ require_capability('moodle/grade:edit', $context);
 // End permission
 
 $_s = function($key, $a = null) {
-    return get_string($key, 'gradereport_quick_edit');
+    return get_string($key, 'gradereport_quick_edit', $a);
 };
 
 $gpr = new grade_plugin_return(array(
diff --git a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
index c000b2d..45361b2 100755
--- a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
+++ b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
@@ -25,3 +25,6 @@
 // General Strings
 $string['pluginname'] = 'Quick Edit';
 $string['quick_edit:view'] = 'View the '.$string['pluginname'].' report';
+
+// Error Strings
+$string['notvalid'] = 'Not a valid Quick Edit screen: {$a}';
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
index 8b05270..254b9f4 100755
--- a/grade/report/quick_edit/lib.php
+++ b/grade/report/quick_edit/lib.php
@@ -27,6 +27,27 @@ require_once($CFG->libdir.'/tablelib.php');
 
 class grade_report_quick_edit extends grade_report {
 
+    public static function valid_types() {
+        $screendir = dirname(__FILE__) . '/screens';
+
+        $is_valid = function($filename) use ($screendir) {
+            if (preg_match('/^\./', $filename)){
+                return false;
+            }
+
+            $file = $screendir . '/' . $filename;
+
+            if (is_file($file)) {
+                return false;
+            }
+
+            $plugin = $file . '/lib.php';
+            return file_exists($plugin);
+        };
+
+        return array_filter(scandir($screendir), $is_valid);
+    }
+
     function process_data($data) {
     }
 
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
new file mode 100644
index 0000000..976ae86
--- /dev/null
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -0,0 +1,4 @@
+<?php
+
+class quick_edit_grade extends quick_edit_screen {
+}
diff --git a/grade/report/quick_edit/screens/user/lib.php b/grade/report/quick_edit/screens/user/lib.php
new file mode 100644
index 0000000..f954812
--- /dev/null
+++ b/grade/report/quick_edit/screens/user/lib.php
@@ -0,0 +1,4 @@
+<?php
+
+class quick_edit_user extends quick_edit_screen {
+}
-- 
1.7.1


From 2d4b9b69f275680351b0497c0b7c2d3a86da8e18 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 3 Feb 2012 10:06:17 -0600
Subject: Exploring dynamic loading

---
 grade/report/quick_edit/classes/lib.php       |   23 ++++++++++++++++++++++-
 grade/report/quick_edit/index.php             |    6 +++---
 grade/report/quick_edit/lib.php               |   17 +++++++++++++++--
 grade/report/quick_edit/screens/grade/lib.php |   18 ++++++++++++++++++
 4 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index beaed35..54c1171 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -1,4 +1,25 @@
 <?php
 
-abstract class quit_edit_screen {
+abstract class quick_edit_screen {
+    var $courseid;
+
+    var $itemid;
+
+    var $groupid;
+
+    var $context;
+
+    function __construct($courseid, $itemid, $groupid = null) {
+        $this->courseid = $courseid;
+        $this->itemid = $itemid;
+        $this->groupid = $groupid;
+
+        $this->context = get_context_instance(CONTEXT_COURSE, $this->courseid);
+
+        $this->init();
+    }
+
+    public abstract function init();
+
+    public abstract function html();
 }
diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index 47e73fe..60121b0 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -28,7 +28,7 @@ require_once $CFG->dirroot.'/grade/lib.php';
 require_once $CFG->dirroot.'/grade/report/quick_edit/lib.php';
 
 $courseid = required_param('id', PARAM_INT);
-$itemtype = optional_param('item', 'grade', PARAM_TEXT);
+$itemtype = optional_param('item', 'select', PARAM_TEXT);
 $itemid = optional_param('itemid', 0, PARAM_INT);
 $groupid  = optional_param('group', null, PARAM_INT);
 
@@ -43,7 +43,7 @@ if (!$course = $DB->get_record('course', array('id' => $courseid))) {
     print_error('nocourseid');
 }
 
-if (!in_array($itemtype, grade_report_quick_edit::valid_types())) {
+if (!in_array($itemtype, grade_report_quick_edit::valid_screens())) {
     print_error('notvalid', 'gradereport_quick_edit', '', $itemtype);
 }
 
@@ -79,7 +79,7 @@ $PAGE->set_context($context);
 print_grade_page_head($course->id, 'report', 'quick_edit', $reportname, false);
 
 $report = new grade_report_quick_edit(
-    $courseid, $gpr, $context, $itemtype, $itemid, $group
+    $courseid, $gpr, $context, $itemtype, $itemid, $groupid
 );
 
 echo $report->output();
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
index 254b9f4..30414c7 100755
--- a/grade/report/quick_edit/lib.php
+++ b/grade/report/quick_edit/lib.php
@@ -23,11 +23,11 @@
 ///////////////////////////////////////////////////////////////////////////
 
 require_once($CFG->dirroot . '/grade/report/lib.php');
-require_once($CFG->libdir.'/tablelib.php');
+require_once($CFG->dirroot . '/grade/report/quick_edit/classes/lib.php');
 
 class grade_report_quick_edit extends grade_report {
 
-    public static function valid_types() {
+    public static function valid_screens() {
         $screendir = dirname(__FILE__) . '/screens';
 
         $is_valid = function($filename) use ($screendir) {
@@ -48,6 +48,14 @@ class grade_report_quick_edit extends grade_report {
         return array_filter(scandir($screendir), $is_valid);
     }
 
+    public static function classname($screen) {
+        $screendir = dirname(__FILE__) . '/screens/' . $screen;
+
+        require_once $screendir . '/lib.php';
+
+        return 'quick_edit_' . $screen;
+    }
+
     function process_data($data) {
     }
 
@@ -60,8 +68,13 @@ class grade_report_quick_edit extends grade_report {
 
     function __construct($courseid, $gpr, $context, $itemtype, $itemid, $groupid=null) {
         parent::__construct($courseid, $gpr, $context);
+
+        $class = self::classname($itemtype);
+
+        $this->screen = new $class($courseid, $itemid, $groupid);
     }
 
     function output() {
+        return $this->screen->html();
     }
 }
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index 976ae86..c75d3bc 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -1,4 +1,22 @@
 <?php
 
 class quick_edit_grade extends quick_edit_screen {
+
+    public function init() {
+        $add = $this->itemid ?
+            array('id' => $this->itemid) :
+            array('itemtype' => 'manual');
+
+        $params = array('courseid' => $this->courseid) + $add;
+
+        $roleids = explode(',', get_config('moodle', 'gradebookroles'));
+
+        $this->item = grade_item::fetch($params);
+
+        $this->users = get_role_users($roleids, $this->context, false, '',
+            'u.lastname, u.firstname', null, $this->groupid);
+    }
+
+    public function html() {
+    }
 }
-- 
1.7.1


From e480970e90be1fe046790bf6cfab1b31f5e76a4c Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 3 Feb 2012 12:25:10 -0600
Subject: Grade screen and grade selector.

---
 grade/report/quick_edit/classes/lib.php        |   61 ++++++++++++++++++++++++
 grade/report/quick_edit/index.php              |   14 ++----
 grade/report/quick_edit/screens/grade/lib.php  |   53 ++++++++++++++++++++
 grade/report/quick_edit/screens/select/lib.php |   36 ++++++++++++++
 4 files changed, 155 insertions(+), 9 deletions(-)
 create mode 100644 grade/report/quick_edit/screens/select/lib.php

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index 54c1171..c85021a 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -19,6 +19,67 @@ abstract class quick_edit_screen {
         $this->init();
     }
 
+    public function format_range($item) {
+        $decimals = $item->get_decimals();
+
+        $min = format_float($item->grademin, $decimals);
+        $max = format_float($item->grademax, $decimals);
+
+        return "$min - $max";
+    }
+
+    public function format_grade($grade, $decimals) {
+        $name = 'grade_' . $grade->itemid . '_' . $grade->userid;
+
+        $finalgrade = $grade->finalgrade ?
+            format_float($grade->finalgrade, $decimals) :
+            '';
+
+        $attributes = array(
+            'type' => 'text',
+            'name' => $name,
+            'value' => $finalgrade
+        );
+
+        $hidden = array(
+            'type' => 'hidden',
+            'name' => 'old' . $name,
+            'value' => $finalgrade
+        );
+
+        return (
+            html_writer::empty_tag('input', $attributes) .
+            html_writer::empty_tag('input', $hidden)
+        );
+    }
+
+    public function format_feedback($grade) {
+        $name = 'feedback_' . $grade->itemid . '_' . $grade->userid;
+
+        $feedback = $grade->feedback ?
+            format_text($grade->feedback, $grade->feedbackformat) :
+            '';
+
+        $attributes = array(
+            'type' => 'text',
+            'name' => $name,
+            'value' => $feedback
+        );
+
+        $hidden = array(
+            'type' => 'hidden',
+            'name' => 'old' . $name,
+            'value' => $feedback
+        );
+
+        return (
+            html_writer::empty_tag('input', $attributes) .
+            html_writer::empty_tag('input', $hidden)
+        );
+    }
+
+    public abstract function heading();
+
     public abstract function init();
 
     public abstract function html();
diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index 60121b0..6e230d4 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -29,7 +29,7 @@ require_once $CFG->dirroot.'/grade/report/quick_edit/lib.php';
 
 $courseid = required_param('id', PARAM_INT);
 $itemtype = optional_param('item', 'select', PARAM_TEXT);
-$itemid = optional_param('itemid', 0, PARAM_INT);
+$itemid = optional_param('itemid', null, PARAM_INT);
 $groupid  = optional_param('group', null, PARAM_INT);
 
 $PAGE->set_url(new moodle_url('/grade/report/quick_edit/index.php', array(
@@ -57,10 +57,6 @@ require_capability('moodle/grade:viewall', $context);
 require_capability('moodle/grade:edit', $context);
 // End permission
 
-$_s = function($key, $a = null) {
-    return get_string($key, 'gradereport_quick_edit', $a);
-};
-
 $gpr = new grade_plugin_return(array(
     'type' => 'report', 'plugin' => 'quick_edit', 'courseid' => $courseid
 ));
@@ -72,16 +68,16 @@ $USER->grade_last_report[$course->id] = 'quick_edit';
 
 grade_regrade_final_grades($courseid);
 
-$reportname = $_s('pluginname');
-
 $PAGE->set_context($context);
 
-print_grade_page_head($course->id, 'report', 'quick_edit', $reportname, false);
-
 $report = new grade_report_quick_edit(
     $courseid, $gpr, $context, $itemtype, $itemid, $groupid
 );
 
+$reportname = $report->screen->heading();
+
+print_grade_page_head($course->id, 'report', 'quick_edit', $reportname, false);
+
 echo $report->output();
 
 echo $OUTPUT->footer();
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index c75d3bc..9b3ba16 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -18,5 +18,58 @@ class quick_edit_grade extends quick_edit_screen {
     }
 
     public function html() {
+        $table = new html_table();
+
+        $table->head = $this->headers();
+
+        $table->data = array();
+
+        foreach ($this->users as $user) {
+            $table->data[] = $this->format_line($user);
+        }
+
+        return html_writer::table($table);
+    }
+
+    public function headers() {
+        return array(
+            '',
+            get_string('firstname') . ' / ' . get_string('lastname'),
+            get_string('range', 'grades'),
+            get_string('grade', 'grades'),
+            get_string('feedback', 'grades')
+        );
+    }
+
+    public function format_line($user) {
+        global $OUTPUT;
+
+        $grade = grade_grade::fetch(array(
+            'itemid' => $this->item->id, 'userid' => $user->id
+        ));
+
+        $fullname = fullname($user);
+
+        $user->imagealt = $fullname;
+
+        return array(
+            $OUTPUT->user_picture($user),
+            $fullname,
+            $this->item_range(),
+            $this->format_grade($grade, $this->item->get_decimals()),
+            $this->format_feedback($grade)
+        );
+    }
+
+    public function item_range() {
+        if (empty($this->range)) {
+            $this->range = $this->format_range($this->item);
+        }
+
+        return $this->range;
+    }
+
+    public function heading() {
+        return $this->item->itemname;
     }
 }
diff --git a/grade/report/quick_edit/screens/select/lib.php b/grade/report/quick_edit/screens/select/lib.php
new file mode 100644
index 0000000..413fb20
--- /dev/null
+++ b/grade/report/quick_edit/screens/select/lib.php
@@ -0,0 +1,36 @@
+<?php
+
+// TODO: custom form with group selector
+class quick_edit_select extends quick_edit_screen {
+    public function init() {
+        global $DB;
+
+        $params = array('courseid' => $this->courseid);
+
+        $filter_items = function($item) {
+            return $item->itemtype != 'course' and $item->itemtype != 'category';
+        };
+
+        $this->grade_items = array_filter(grade_item::fetch_all($params), $filter_items);
+
+        $this->item = $DB->get_record('course', array('id' => $this->courseid));
+    }
+
+    public function html() {
+        global $OUTPUT;
+
+        $map = function($item) { return $item->itemname; };
+
+        $grade_options = array_map($map, $this->grade_items);
+
+        $params = array(
+            'id' => $this->courseid,
+            'item' => 'grade',
+            'group' => $this->groupid
+        );
+
+        $url = new moodle_url('/grade/report/quick_edit/index.php', $params);
+
+        echo $OUTPUT->single_select($url, 'itemid', $grade_options, $this->itemid);
+    }
+}
-- 
1.7.1


From f68b35591cd915e1ef273d9f6317ff28dc241bc7 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 3 Feb 2012 13:49:40 -0600
Subject: Interconnecting Screens.

---
 grade/report/quick_edit/classes/lib.php            |   56 +++++++++++++++-
 grade/report/quick_edit/index.php                  |   28 +++++---
 .../quick_edit/lang/en/gradereport_quick_edit.php  |    5 ++
 grade/report/quick_edit/lib.php                    |    6 ++
 grade/report/quick_edit/screens/grade/lib.php      |    2 +-
 grade/report/quick_edit/screens/select/lib.php     |    4 +-
 grade/report/quick_edit/screens/user/lib.php       |   74 ++++++++++++++++++++
 7 files changed, 161 insertions(+), 14 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index c85021a..78636b0 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -19,6 +19,21 @@ abstract class quick_edit_screen {
         $this->init();
     }
 
+    public function format_link($screen, $itemid, $display = null) {
+        $url = new moodle_url('/grade/report/quick_edit/index.php', array(
+            'id' => $this->courseid,
+            'item' => $screen,
+            'itemid' => $itemid,
+            'group' => $this->groupid
+        ));
+
+        if ($display) {
+            return html_writer::link($url, $display);
+        } else {
+            return $url;
+        }
+    }
+
     public function format_range($item) {
         $decimals = $item->get_decimals();
 
@@ -28,6 +43,43 @@ abstract class quick_edit_screen {
         return "$min - $max";
     }
 
+    public function format_override($item, $grade) {
+        if ($item->itemtype == 'manual') {
+            return get_string('notavailable', 'gradereport_quick_edit');
+        }
+
+        return $this->checkbox_attribute($grade, 'override', $grade->is_overridden());
+    }
+
+    public function format_exclude($item, $grade) {
+        return $this->checkbox_attribute($grade, 'excldue', $grade->is_excluded());
+    }
+
+    private function checkbox_attribute($grade, $post_name, $is_checked) {
+        $name = $post_name . '_' . $grade->itemid . '_' . $grade->userid;
+
+        $attributes = array(
+            'type' => 'checkbox',
+            'name' => $name,
+            'value' => 1
+        );
+
+        $hidden = array(
+            'type' => 'hidden',
+            'name' => 'old' . $name
+        );
+
+        if ($is_checked) {
+            $attributes['checked'] = 'CHECKED';
+            $hidden['value'] = 1;
+        }
+
+        return (
+            html_writer::empty_tag('input', $attributes) .
+            html_writer::empty_tag('input', $hidden)
+        );
+    }
+
     public function format_grade($grade, $decimals) {
         $name = 'grade_' . $grade->itemid . '_' . $grade->userid;
 
@@ -78,7 +130,9 @@ abstract class quick_edit_screen {
         );
     }
 
-    public abstract function heading();
+    public function heading() {
+        return get_string('pluginname', 'gradereport_quick_edit');
+    }
 
     public abstract function init();
 
diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index 6e230d4..3f11e5b 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -39,7 +39,9 @@ $PAGE->set_url(new moodle_url('/grade/report/quick_edit/index.php', array(
     'group' => $groupid
 )));
 
-if (!$course = $DB->get_record('course', array('id' => $courseid))) {
+$course_params = array('id' => $courseid);
+
+if (!$course = $DB->get_record('course', $course_params)) {
     print_error('nocourseid');
 }
 
@@ -61,22 +63,30 @@ $gpr = new grade_plugin_return(array(
     'type' => 'report', 'plugin' => 'quick_edit', 'courseid' => $courseid
 ));
 
-if (!isset($USER->grade_last_report)) {
-    $USER->grade_last_report = array();
-}
-$USER->grade_last_report[$course->id] = 'quick_edit';
-
 grade_regrade_final_grades($courseid);
 
-$PAGE->set_context($context);
-
 $report = new grade_report_quick_edit(
     $courseid, $gpr, $context, $itemtype, $itemid, $groupid
 );
 
 $reportname = $report->screen->heading();
 
-print_grade_page_head($course->id, 'report', 'quick_edit', $reportname, false);
+$pluginname = get_string('pluginname', 'gradereport_quick_edit');
+
+$report_url = new moodle_url('/grade/report/index.php', $course_params);
+$edit_url = new moodle_url('/grade/report/quick_edit/index.php', $course_params);
+
+$PAGE->navbar->add(get_string('gradeadministration', 'grades'));
+$PAGE->navbar->add(get_string('pluginname', 'gradereport_grader'), $report_url);
+
+if ($reportname != $pluginname) {
+    $PAGE->navbar->add($pluginname, $edit_url);
+    $PAGE->navbar->add($reportname);
+} else {
+    $PAGE->navbar->add($pluginname);
+}
+
+print_grade_page_head($course->id, 'report', 'quick_edit', $reportname);
 
 echo $report->output();
 
diff --git a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
index 45361b2..a157bf7 100755
--- a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
+++ b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
@@ -26,5 +26,10 @@
 $string['pluginname'] = 'Quick Edit';
 $string['quick_edit:view'] = 'View the '.$string['pluginname'].' report';
 
+$string['exclude'] = 'Exclude';
+$string['override'] = 'Override';
+$string['assessmentname'] = 'Assessment Name';
+$string['notavailable'] = 'NA';
+
 // Error Strings
 $string['notvalid'] = 'Not a valid Quick Edit screen: {$a}';
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
index 30414c7..d136324 100755
--- a/grade/report/quick_edit/lib.php
+++ b/grade/report/quick_edit/lib.php
@@ -56,6 +56,12 @@ class grade_report_quick_edit extends grade_report {
         return 'quick_edit_' . $screen;
     }
 
+    public static function only_items() {
+        return function($item) {
+            return $item->itemtype != 'course' and $item->itemtype != 'category';
+        };
+    }
+
     function process_data($data) {
     }
 
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index 9b3ba16..51a5507 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -54,7 +54,7 @@ class quick_edit_grade extends quick_edit_screen {
 
         return array(
             $OUTPUT->user_picture($user),
-            $fullname,
+            $this->format_link('user', $user->id, $fullname),
             $this->item_range(),
             $this->format_grade($grade, $this->item->get_decimals()),
             $this->format_feedback($grade)
diff --git a/grade/report/quick_edit/screens/select/lib.php b/grade/report/quick_edit/screens/select/lib.php
index 413fb20..be87f26 100644
--- a/grade/report/quick_edit/screens/select/lib.php
+++ b/grade/report/quick_edit/screens/select/lib.php
@@ -7,9 +7,7 @@ class quick_edit_select extends quick_edit_screen {
 
         $params = array('courseid' => $this->courseid);
 
-        $filter_items = function($item) {
-            return $item->itemtype != 'course' and $item->itemtype != 'category';
-        };
+        $filter_items = grade_report_quick_edit::only_items();
 
         $this->grade_items = array_filter(grade_item::fetch_all($params), $filter_items);
 
diff --git a/grade/report/quick_edit/screens/user/lib.php b/grade/report/quick_edit/screens/user/lib.php
index f954812..6f6c469 100644
--- a/grade/report/quick_edit/screens/user/lib.php
+++ b/grade/report/quick_edit/screens/user/lib.php
@@ -1,4 +1,78 @@
 <?php
 
 class quick_edit_user extends quick_edit_screen {
+
+    private $categories = array();
+
+    public function init() {
+        global $DB;
+
+        $this->user = $DB->get_record('user', array('id' => $this->itemid));
+
+        $params = array('courseid' => $this->courseid);
+
+        $filter_items = grade_report_quick_edit::only_items();
+
+        $this->grade_items = array_filter(grade_item::fetch_all($params), $filter_items);
+    }
+
+    public function html() {
+        $table = new html_table();
+
+        $table->head = $this->headers();
+
+        $table->data = array();
+
+        foreach ($this->grade_items as $item) {
+            $table->data[] = $this->format_line($item);
+        }
+
+        return html_writer::table($table);
+    }
+
+    public function headers() {
+        return array(
+            '',
+            get_string('assessmentname', 'gradereport_quick_edit'),
+            get_string('gradecategory', 'grades'),
+            get_string('range', 'grades'),
+            get_string('grade', 'grades'),
+            get_string('feedback', 'grades'),
+            get_string('override', 'gradereport_quick_edit'),
+            get_string('exclude', 'gradereport_quick_edit')
+        );
+    }
+
+    public function format_line($item) {
+        global $OUTPUT;
+
+        $grade = grade_grade::fetch(array(
+            'itemid' => $item->id, 'userid' => $this->user->id
+        ));
+
+        return array(
+            $OUTPUT->pix_icon('t/' . $item->itemtype . '_item', $item->itemname),
+            $this->format_link('grade', $item->id, $item->itemname),
+            $this->category($item)->get_name(),
+            $this->format_range($item),
+            $this->format_grade($grade, $item->get_decimals()),
+            $this->format_feedback($grade),
+            $this->format_override($item, $grade),
+            $this->format_exclude($item, $grade)
+        );
+    }
+
+    private function category($item) {
+        if (!isset($this->categories[$item->categoryid])) {
+            $category = $item->get_parent_category();
+
+            $this->categories[$category->id] = $category;
+        }
+
+        return $this->categories[$item->categoryid];
+    }
+
+    public function heading() {
+        return fullname($this->user);
+    }
 }
-- 
1.7.1


From 9ef79116c1e3e4a26d388bbf4172bad2ea3a80e0 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 3 Feb 2012 14:46:47 -0600
Subject: Interface checks on itemtypes

---
 grade/report/quick_edit/classes/lib.php       |   41 ++++++++++++++++++++++++-
 grade/report/quick_edit/screens/grade/lib.php |   32 ++++++++++++++++---
 grade/report/quick_edit/screens/user/lib.php  |   20 ++++++++----
 3 files changed, 81 insertions(+), 12 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index 78636b0..5c7fa34 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -52,7 +52,46 @@ abstract class quick_edit_screen {
     }
 
     public function format_exclude($item, $grade) {
-        return $this->checkbox_attribute($grade, 'excldue', $grade->is_excluded());
+        return $this->checkbox_attribute($grade, 'exclude', $grade->is_excluded());
+    }
+
+    public function fetch_grade_or_default($item, $user) {
+        $grade = grade_grade::fetch(array(
+            'itemid' => $item->id, 'userid' => $user->id
+        ));
+
+        if (!$grade) {
+            $default = new stdClass;
+
+            $default->userid = $user->id;
+            $default->itemid = $item->id;
+            $default->feedback = '';
+
+            $grade = new grade_grade($default, false);
+        }
+
+        return $grade;
+    }
+
+    public function make_toggle($key) {
+        $attrs = array('href' => '#');
+
+        $all = html_writer::tag('a', get_string('all'), $attrs + array(
+            'class' => 'include_all ' . $key
+        ));
+
+        $none = html_writer::tag('a', get_string('none'), $attrs + array(
+            'class' => 'include_none ' . $key
+        ));
+
+        return html_writer::tag('span', "$all / $none", array(
+            'class' => 'inclusion_links'
+        ));
+    }
+
+    public function make_toggle_links($key) {
+        return get_string($key, 'gradereport_quick_edit') . ' ' .
+            $this->make_toggle($key);
     }
 
     private function checkbox_attribute($grade, $post_name, $is_checked) {
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index 51a5507..14eff7e 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -2,6 +2,8 @@
 
 class quick_edit_grade extends quick_edit_screen {
 
+    private $requires_extra;
+
     public function init() {
         $add = $this->itemid ?
             array('id' => $this->itemid) :
@@ -15,6 +17,8 @@ class quick_edit_grade extends quick_edit_screen {
 
         $this->users = get_role_users($roleids, $this->context, false, '',
             'u.lastname, u.firstname', null, $this->groupid);
+
+        $this->requires_extra = $this->item->itemtype != 'manual';
     }
 
     public function html() {
@@ -32,33 +36,51 @@ class quick_edit_grade extends quick_edit_screen {
     }
 
     public function headers() {
-        return array(
+        $headers = array(
             '',
             get_string('firstname') . ' / ' . get_string('lastname'),
             get_string('range', 'grades'),
             get_string('grade', 'grades'),
             get_string('feedback', 'grades')
         );
+
+        return $this->additional_headers($headers);
     }
 
     public function format_line($user) {
         global $OUTPUT;
 
-        $grade = grade_grade::fetch(array(
-            'itemid' => $this->item->id, 'userid' => $user->id
-        ));
+        $grade = $this->fetch_grade_or_default($this->item, $user);
 
         $fullname = fullname($user);
 
         $user->imagealt = $fullname;
 
-        return array(
+        $line = array(
             $OUTPUT->user_picture($user),
             $this->format_link('user', $user->id, $fullname),
             $this->item_range(),
             $this->format_grade($grade, $this->item->get_decimals()),
             $this->format_feedback($grade)
         );
+
+        return $this->additional_cells($line, $grade);
+    }
+
+    public function additional_cells($line, $grade) {
+        if ($this->requires_extra) {
+            $line[] = $this->format_override($this->item, $grade);
+        }
+
+        return $line;
+    }
+
+    public function additional_headers($headers) {
+        if ($this->requires_extra) {
+            $headers[] = $this->make_toggle_links('override');
+        }
+
+        return $headers;
     }
 
     public function item_range() {
diff --git a/grade/report/quick_edit/screens/user/lib.php b/grade/report/quick_edit/screens/user/lib.php
index 6f6c469..d5f1520 100644
--- a/grade/report/quick_edit/screens/user/lib.php
+++ b/grade/report/quick_edit/screens/user/lib.php
@@ -4,6 +4,8 @@ class quick_edit_user extends quick_edit_screen {
 
     private $categories = array();
 
+    private $structure;
+
     public function init() {
         global $DB;
 
@@ -14,6 +16,8 @@ class quick_edit_user extends quick_edit_screen {
         $filter_items = grade_report_quick_edit::only_items();
 
         $this->grade_items = array_filter(grade_item::fetch_all($params), $filter_items);
+
+        $this->structure = new grade_structure();
     }
 
     public function html() {
@@ -38,20 +42,18 @@ class quick_edit_user extends quick_edit_screen {
             get_string('range', 'grades'),
             get_string('grade', 'grades'),
             get_string('feedback', 'grades'),
-            get_string('override', 'gradereport_quick_edit'),
-            get_string('exclude', 'gradereport_quick_edit')
+            $this->make_toggle_links('override'),
+            $this->make_toggle_links('exclude')
         );
     }
 
     public function format_line($item) {
         global $OUTPUT;
 
-        $grade = grade_grade::fetch(array(
-            'itemid' => $item->id, 'userid' => $this->user->id
-        ));
+        $grade = $this->fetch_grade_or_default($item, $this->user);
 
         return array(
-            $OUTPUT->pix_icon('t/' . $item->itemtype . '_item', $item->itemname),
+            $this->format_icon($item),
             $this->format_link('grade', $item->id, $item->itemname),
             $this->category($item)->get_name(),
             $this->format_range($item),
@@ -62,6 +64,12 @@ class quick_edit_user extends quick_edit_screen {
         );
     }
 
+    private function format_icon($item) {
+        $element = array('type' => 'item', 'object' => $item);
+
+        return $this->structure->get_element_icon($element);
+    }
+
     private function category($item) {
         if (!isset($this->categories[$item->categoryid])) {
             $category = $item->get_parent_category();
-- 
1.7.1


From a53c00380bfa51438632f0cd3cfa8c850f1fe31e Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 3 Feb 2012 15:05:04 -0600
Subject: Making better use of internal grade API

---
 grade/report/quick_edit/classes/lib.php       |   62 ++++++++++++------------
 grade/report/quick_edit/screens/grade/lib.php |    4 +-
 grade/report/quick_edit/screens/user/lib.php  |    6 +-
 3 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index 5c7fa34..be2f623 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -43,15 +43,15 @@ abstract class quick_edit_screen {
         return "$min - $max";
     }
 
-    public function format_override($item, $grade) {
-        if ($item->itemtype == 'manual') {
+    public function format_override($grade) {
+        if (!$grade->grade_item->is_overridable_item()) {
             return get_string('notavailable', 'gradereport_quick_edit');
         }
 
         return $this->checkbox_attribute($grade, 'override', $grade->is_overridden());
     }
 
-    public function format_exclude($item, $grade) {
+    public function format_exclude($grade) {
         return $this->checkbox_attribute($grade, 'exclude', $grade->is_excluded());
     }
 
@@ -70,6 +70,8 @@ abstract class quick_edit_screen {
             $grade = new grade_grade($default, false);
         }
 
+        $grade->grade_item = $item;
+
         return $grade;
     }
 
@@ -94,7 +96,7 @@ abstract class quick_edit_screen {
             $this->make_toggle($key);
     }
 
-    private function checkbox_attribute($grade, $post_name, $is_checked) {
+    protected function checkbox_attribute($grade, $post_name, $is_checked) {
         $name = $post_name . '_' . $grade->itemid . '_' . $grade->userid;
 
         $attributes = array(
@@ -119,48 +121,50 @@ abstract class quick_edit_screen {
         );
     }
 
-    public function format_grade($grade, $decimals) {
-        $name = 'grade_' . $grade->itemid . '_' . $grade->userid;
-
+    public function format_grade($grade) {
         $finalgrade = $grade->finalgrade ?
-            format_float($grade->finalgrade, $decimals) :
+            format_float($grade->finalgrade, $grade->grade_item->get_decimals()) :
             '';
 
-        $attributes = array(
-            'type' => 'text',
-            'name' => $name,
-            'value' => $finalgrade
-        );
-
-        $hidden = array(
-            'type' => 'hidden',
-            'name' => 'old' . $name,
-            'value' => $finalgrade
-        );
+        $is_disabled = ($grade->grade_item->is_overridable_item() and !$grade->is_overridden());
 
-        return (
-            html_writer::empty_tag('input', $attributes) .
-            html_writer::empty_tag('input', $hidden)
-        );
+        return $this->text_attribute($grade, 'grade', $finalgrade, $is_disabled);
     }
 
     public function format_feedback($grade) {
-        $name = 'feedback_' . $grade->itemid . '_' . $grade->userid;
-
         $feedback = $grade->feedback ?
             format_text($grade->feedback, $grade->feedbackformat) :
             '';
 
+        $is_disabled = (
+            $grade->grade_item->is_overridable_item_feedback() and
+            !$grade->is_overridden()
+        );
+
+        return $this->text_attribute($grade, 'feedback', $feedback, $is_disabled);
+    }
+
+    public function heading() {
+        return get_string('pluginname', 'gradereport_quick_edit');
+    }
+
+    protected function text_attribute($grade, $post_name, $value, $is_disabled = false) {
+        $name = $post_name . '_' . $grade->itemid . '_' . $grade->userid;
+
         $attributes = array(
             'type' => 'text',
             'name' => $name,
-            'value' => $feedback
+            'value' => $value
         );
 
+        if ($is_disabled) {
+            $attributes['disabled'] = 'DISABLED';
+        }
+
         $hidden = array(
             'type' => 'hidden',
             'name' => 'old' . $name,
-            'value' => $feedback
+            'value' => $value
         );
 
         return (
@@ -169,10 +173,6 @@ abstract class quick_edit_screen {
         );
     }
 
-    public function heading() {
-        return get_string('pluginname', 'gradereport_quick_edit');
-    }
-
     public abstract function init();
 
     public abstract function html();
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index 14eff7e..eaa1833 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -60,7 +60,7 @@ class quick_edit_grade extends quick_edit_screen {
             $OUTPUT->user_picture($user),
             $this->format_link('user', $user->id, $fullname),
             $this->item_range(),
-            $this->format_grade($grade, $this->item->get_decimals()),
+            $this->format_grade($grade),
             $this->format_feedback($grade)
         );
 
@@ -69,7 +69,7 @@ class quick_edit_grade extends quick_edit_screen {
 
     public function additional_cells($line, $grade) {
         if ($this->requires_extra) {
-            $line[] = $this->format_override($this->item, $grade);
+            $line[] = $this->format_override($grade);
         }
 
         return $line;
diff --git a/grade/report/quick_edit/screens/user/lib.php b/grade/report/quick_edit/screens/user/lib.php
index d5f1520..3895cdc 100644
--- a/grade/report/quick_edit/screens/user/lib.php
+++ b/grade/report/quick_edit/screens/user/lib.php
@@ -57,10 +57,10 @@ class quick_edit_user extends quick_edit_screen {
             $this->format_link('grade', $item->id, $item->itemname),
             $this->category($item)->get_name(),
             $this->format_range($item),
-            $this->format_grade($grade, $item->get_decimals()),
+            $this->format_grade($grade),
             $this->format_feedback($grade),
-            $this->format_override($item, $grade),
-            $this->format_exclude($item, $grade)
+            $this->format_override($grade),
+            $this->format_exclude($grade)
         );
     }
 
-- 
1.7.1


From d8b4eb04a7d0e6d30b654fd1d789935c56c7b6c6 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 3 Feb 2012 15:25:00 -0600
Subject: Pluggable post processor.

---
 grade/report/quick_edit/classes/lib.php       |   13 +++++++++++++
 grade/report/quick_edit/screens/grade/lib.php |   11 +++++------
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index be2f623..b46998a 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -1,5 +1,14 @@
 <?php
 
+abstract class post_processor {
+    abstract class function handle($data);
+}
+
+class quick_edit_grade_processor extends post_processor {
+    function handle($data) {
+    }
+}
+
 abstract class quick_edit_screen {
     var $courseid;
 
@@ -176,4 +185,8 @@ abstract class quick_edit_screen {
     public abstract function init();
 
     public abstract function html();
+
+    public function processor() {
+        return new quick_edit_grade_processor();
+    }
 }
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index eaa1833..39e3e9b 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -5,11 +5,10 @@ class quick_edit_grade extends quick_edit_screen {
     private $requires_extra;
 
     public function init() {
-        $add = $this->itemid ?
-            array('id' => $this->itemid) :
-            array('itemtype' => 'manual');
-
-        $params = array('courseid' => $this->courseid) + $add;
+        $params = array(
+            'id' => $this->itemid,
+            'courseid' => $this->courseid
+        );
 
         $roleids = explode(',', get_config('moodle', 'gradebookroles'));
 
@@ -18,7 +17,7 @@ class quick_edit_grade extends quick_edit_screen {
         $this->users = get_role_users($roleids, $this->context, false, '',
             'u.lastname, u.firstname', null, $this->groupid);
 
-        $this->requires_extra = $this->item->itemtype != 'manual';
+        $this->requires_extra = !$this->item->is_manual_item();
     }
 
     public function html() {
-- 
1.7.1


From eae9d9732a593b0d3e4238f99ac75778da7f792c Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 6 Feb 2012 13:01:59 -0600
Subject: Pluggable backend processor.

---
 grade/report/quick_edit/classes/datalib.php |  163 +++++++++++++++++++++++++++
 1 files changed, 163 insertions(+), 0 deletions(-)
 create mode 100644 grade/report/quick_edit/classes/datalib.php

diff --git a/grade/report/quick_edit/classes/datalib.php b/grade/report/quick_edit/classes/datalib.php
new file mode 100644
index 0000000..8930e30
--- /dev/null
+++ b/grade/report/quick_edit/classes/datalib.php
@@ -0,0 +1,163 @@
+<?php
+
+abstract class post_processor {
+    function __construct($courseid) {
+        $this->courseid = $courseid;
+    }
+
+    abstract function handle($data);
+}
+
+class quick_edit_grade_processor extends post_processor {
+    function get_fields() {
+        return array(
+            'finalgrade', 'feedback', 'override', 'exclude'
+        );
+    }
+
+    function handle($data) {
+        foreach ($data as $varname => $throw) {
+            if (preg_match("/(\w+)_(\d+)_(\d+)/", $varname, $matches)) {
+                $itemid = $matches[2];
+                $userid = $matches[3];
+            } else {
+                continue;
+            }
+
+            $grade_item = grade_item::fetch(array(
+                'id' => $itemid, 'courseid' => $this->courseid
+            ));
+
+            if (!$grade_item) {
+                continue;
+            }
+
+            $fields = $this->get_fields();
+
+            $warnings = array();
+            foreach ($fields as $field) {
+
+                $name = "{$field}_{$itemid}_{$userid}";
+                $oldname = "old$name";
+
+                // Probably not supported
+                if (empty($data->$name) and empty($data->$oldname)) {
+                    continue;
+                }
+
+                // Probably a checkbox
+                if (!isset($data->$name) and isset($data->$oldname)) {
+                    $data->$name = 0;
+                }
+
+                $posted = $data->$name;
+                $oldvalue = $data->$oldname;
+
+                // Same value; skip
+                if ($oldvalue == $posted) {
+                    continue;
+                }
+
+                $func = 'set_' . $field;
+
+                $msg = $this->{$func}($grade_item, $userid, $posted);
+
+                // Optional type
+                if (!empty($msg)) {
+                    $warnings[] = $msg;
+                }
+            }
+        }
+
+        return $warnings;
+    }
+
+    function set_finalgrade($grade_item, $userid, $value) {
+        global $DB;
+
+        $feedback = false;
+        $feedbackformat = false;
+        if ($grade_item->gradetype == GRADE_TYPE_SCALE) {
+            if ($posted == -1) {
+                $finalgrade = null;
+            } else {
+                $finalgrade = $posted;
+            }
+        } else {
+            $finalgrade = unformat_float($posted);
+        }
+
+        $errorstr = '';
+        if (is_null($finalgrade)) {
+            // ok
+        } else {
+            $bounded = $grade_item->bounded_grade($finalgrade);
+            if ($bounded > $finalgrade) {
+                $errorstr = 'lessthanmin';
+            } else if ($bounded < $finalgrade) {
+                $errorstr = 'morethanmax';
+            }
+        }
+
+        if ($errorstr) {
+            $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
+            $gradestr = new stdClass;
+            $gradestr->username = fullname($user);
+            $gradestr->itemname = $grade_item->get_name();
+
+            return get_string($errorstr, 'grades', $gradestr);
+        }
+
+        $grade_item->update_final_grade($userid, $finalgrade, 'quick_edit', $feedback, FORMAT_MOODLE);
+        return false;
+    }
+
+    function set_feedback($grade_item, $userid, $value) {
+        $finalgrade = false;
+        $trimmed = trim($value);
+        if (empty($trimmed)) {
+            $feedback = NULL;
+        } else {
+            $feedback = $value;
+        }
+
+        $grade_item->update_final_grade($userid, $finalgrade, 'quick_edit', $feedback, FORMAT_MOODLE);
+    }
+
+    function set_override($grade_item, $userid, $value) {
+        $grade = grade_grade::fetch(array(
+            'itemid' => $grade_item->id, 'userid' => $userid
+        ));
+
+        if (empty($grade)) {
+            return false;
+        }
+
+        $state = $value == 0 ? false : true;
+
+        return !$grade->set_overridden($state);
+    }
+
+    function set_exclude($grade_item, $userid, $value) {
+        $grade_params = array(
+            'itemid' => $grade_item->id, 'userid' => $userid
+        );
+
+        $grade = grade_grade::fetch($grade_params);
+
+        if (empty($grade)) {
+            if (empty($value)) {
+                return false;
+            }
+
+            // Fill in arbitrary grade to be excluded
+            $grade_item->update_final_grade($userid, null, 'quick_edit', null, FORMAT_MOODLE);
+
+            $grade = grade_grade::fetch($grade_params);
+        }
+
+        $state = $value == 0 ? false : true;
+
+        return !$grade->set_excluded($state);
+    }
+}
-- 
1.7.1


From f9a28fc9c3498fbafc009887a20204bdcc7ef0f3 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 6 Feb 2012 13:13:54 -0600
Subject: UI factory for customizable elements

---
 grade/report/quick_edit/classes/lib.php       |  120 +++---------
 grade/report/quick_edit/classes/uilib.php     |  252 +++++++++++++++++++++++++
 grade/report/quick_edit/screens/grade/lib.php |   46 ++---
 grade/report/quick_edit/screens/user/lib.php  |   32 +--
 4 files changed, 309 insertions(+), 141 deletions(-)
 create mode 100644 grade/report/quick_edit/classes/uilib.php

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index b46998a..ab76819 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -1,13 +1,7 @@
 <?php
 
-abstract class post_processor {
-    abstract class function handle($data);
-}
-
-class quick_edit_grade_processor extends post_processor {
-    function handle($data) {
-    }
-}
+require_once $CFG->dirroot . '/grade/report/quick_edit/classes/uilib.php';
+require_once $CFG->dirroot . '/grade/report/quick_edit/classes/datalib.php';
 
 abstract class quick_edit_screen {
     var $courseid;
@@ -43,27 +37,6 @@ abstract class quick_edit_screen {
         }
     }
 
-    public function format_range($item) {
-        $decimals = $item->get_decimals();
-
-        $min = format_float($item->grademin, $decimals);
-        $max = format_float($item->grademax, $decimals);
-
-        return "$min - $max";
-    }
-
-    public function format_override($grade) {
-        if (!$grade->grade_item->is_overridable_item()) {
-            return get_string('notavailable', 'gradereport_quick_edit');
-        }
-
-        return $this->checkbox_attribute($grade, 'override', $grade->is_overridden());
-    }
-
-    public function format_exclude($grade) {
-        return $this->checkbox_attribute($grade, 'exclude', $grade->is_excluded());
-    }
-
     public function fetch_grade_or_default($item, $user) {
         $grade = grade_grade::fetch(array(
             'itemid' => $item->id, 'userid' => $user->id
@@ -105,88 +78,45 @@ abstract class quick_edit_screen {
             $this->make_toggle($key);
     }
 
-    protected function checkbox_attribute($grade, $post_name, $is_checked) {
-        $name = $post_name . '_' . $grade->itemid . '_' . $grade->userid;
+    public function heading() {
+        return get_string('pluginname', 'gradereport_quick_edit');
+    }
 
-        $attributes = array(
-            'type' => 'checkbox',
-            'name' => $name,
-            'value' => 1
-        );
+    public abstract function init();
 
-        $hidden = array(
-            'type' => 'hidden',
-            'name' => 'old' . $name
-        );
+    public abstract function html();
 
-        if ($is_checked) {
-            $attributes['checked'] = 'CHECKED';
-            $hidden['value'] = 1;
+    public function factory() {
+        if (empty($this->__factory)) {
+            $this->__factory = new quick_edit_grade_ui_factory();
         }
 
-        return (
-            html_writer::empty_tag('input', $attributes) .
-            html_writer::empty_tag('input', $hidden)
-        );
+        return $this->__factory;
     }
 
-    public function format_grade($grade) {
-        $finalgrade = $grade->finalgrade ?
-            format_float($grade->finalgrade, $grade->grade_item->get_decimals()) :
-            '';
-
-        $is_disabled = ($grade->grade_item->is_overridable_item() and !$grade->is_overridden());
-
-        return $this->text_attribute($grade, 'grade', $finalgrade, $is_disabled);
+    public function processor() {
+        return new quick_edit_grade_processor($this->courseid);
     }
+}
 
-    public function format_feedback($grade) {
-        $feedback = $grade->feedback ?
-            format_text($grade->feedback, $grade->feedbackformat) :
-            '';
+abstract class quick_edit_tablelike extends quick_edit_screen {
+    var $items;
 
-        $is_disabled = (
-            $grade->grade_item->is_overridable_item_feedback() and
-            !$grade->is_overridden()
-        );
+    public abstract function headers();
 
-        return $this->text_attribute($grade, 'feedback', $feedback, $is_disabled);
-    }
+    public abstract function format_line($item);
 
-    public function heading() {
-        return get_string('pluginname', 'gradereport_quick_edit');
-    }
+    public function html() {
+        $table = new html_table();
 
-    protected function text_attribute($grade, $post_name, $value, $is_disabled = false) {
-        $name = $post_name . '_' . $grade->itemid . '_' . $grade->userid;
+        $table->head = $this->headers();
 
-        $attributes = array(
-            'type' => 'text',
-            'name' => $name,
-            'value' => $value
-        );
+        $table->data = array();
 
-        if ($is_disabled) {
-            $attributes['disabled'] = 'DISABLED';
+        foreach ($this->items as $item) {
+            $table->data[] = $this->format_line($item);
         }
 
-        $hidden = array(
-            'type' => 'hidden',
-            'name' => 'old' . $name,
-            'value' => $value
-        );
-
-        return (
-            html_writer::empty_tag('input', $attributes) .
-            html_writer::empty_tag('input', $hidden)
-        );
-    }
-
-    public abstract function init();
-
-    public abstract function html();
-
-    public function processor() {
-        return new quick_edit_grade_processor();
+        return html_writer::table($table);
     }
 }
diff --git a/grade/report/quick_edit/classes/uilib.php b/grade/report/quick_edit/classes/uilib.php
new file mode 100644
index 0000000..e36a0dc
--- /dev/null
+++ b/grade/report/quick_edit/classes/uilib.php
@@ -0,0 +1,252 @@
+<?php
+
+abstract class quick_edit_ui_factory {
+    public abstract function create($type);
+
+    protected function wrap($class) {
+        return new quick_edit_factory_class_wrap($class);
+    }
+}
+
+class quick_edit_grade_ui_factory extends quick_edit_ui_factory {
+    public function create($type) {
+        return $this->wrap("quick_edit_{$type}_ui");
+    }
+}
+
+class quick_edit_factory_class_wrap {
+    function __construct($class) {
+        $this->class = $class;
+    }
+
+    function format($what) {
+        return new $this->class($what);
+    }
+}
+
+abstract class quick_edit_ui_element {
+    var $name;
+    var $value;
+
+    function __construct($name, $value) {
+        $this->name = $name;
+        $this->value = $value;
+    }
+
+    abstract function html();
+}
+
+class quick_edit_empty_element extends quick_edit_ui_element {
+    function __construct($msg = null) {
+        if (is_null($msg)) {
+            $this->text = get_string('notavailable', 'gradereport_quick_edit');
+        } else {
+            $this->text = $msg;
+        }
+    }
+
+    function html() {
+        return $this->text;
+    }
+}
+
+class quick_edit_text_attribute extends quick_edit_ui_element {
+    var $is_disabled;
+
+    function __construct($name, $value, $is_disabled = false) {
+        $this->is_disabled = $is_disabled;
+        parent::__construct($name, $value);
+    }
+
+    function html() {
+        $attributes = array(
+            'type' => 'text',
+            'name' => $this->name,
+            'value' => $this->value
+        );
+
+        if ($this->is_disabled) {
+            $attributes['disabled'] = 'DISABLED';
+        }
+
+        $hidden = array(
+            'type' => 'hidden',
+            'name' => 'old' . $this->name,
+            'value' => $this->value
+        );
+
+        return (
+            html_writer::empty_tag('input', $attributes) .
+            html_writer::empty_tag('input', $hidden)
+        );
+    }
+}
+
+class quick_edit_checkbox_attribute extends quick_edit_ui_element {
+    var $is_checked;
+
+    function __construct($name, $is_checked = false) {
+        $this->is_checked = $is_checked;
+        parent::__construct($name, 1);
+    }
+
+    function html() {
+        $attributes = array(
+            'type' => 'checkbox',
+            'name' => $this->name,
+            'value' => 1
+        );
+
+        $hidden = array(
+            'type' => 'hidden',
+            'name' => 'old' . $this->name
+        );
+
+        if ($this->is_checked) {
+            $attributes['checked'] = 'CHECKED';
+            $hidden['value'] = 1;
+        }
+
+        return (
+            html_writer::empty_tag('input', $attributes) .
+            html_writer::empty_tag('input', $hidden)
+        );
+    }
+}
+
+abstract class quick_edit_attribute_format {
+    abstract function determine_format();
+
+    function __toString() {
+        return $this->determine_format()->html();
+    }
+}
+
+abstract class quick_edit_grade_attribute_format extends quick_edit_attribute_format implements unique_name {
+    var $name;
+
+    function __construct($grade) {
+        $this->grade = $grade;
+    }
+
+    function get_name() {
+        return "{$this->name}_{$this->grade->itemid}_{$this->grade->userid}";
+    }
+}
+
+interface unique_name {
+    function get_name();
+}
+
+interface unique_value {
+    function get_value();
+}
+
+interface be_disabled {
+    function is_disabled();
+}
+
+interface be_checked {
+    function is_checked();
+}
+
+class quick_edit_finalgrade_ui extends quick_edit_grade_attribute_format implements unique_value, be_disabled {
+
+    var $name = 'finalgrade';
+
+    function get_value() {
+        return $this->grade->finalgrade ?
+            format_float($this->grade->finalgrade, $this->grade->grade_item->get_decimals()) :
+            '';
+    }
+
+    function is_disabled() {
+        return (
+            $this->grade->grade_item->is_overridable_item() and
+            !$this->grade->is_overridden()
+        );
+    }
+
+    function determine_format() {
+        return new quick_edit_text_attribute(
+            $this->get_name(),
+            $this->get_value(),
+            $this->is_disabled()
+        );
+    }
+}
+
+class quick_edit_feedback_ui extends quick_edit_grade_attribute_format implements unique_value, be_disabled {
+
+    var $name = 'feedback';
+
+    function get_value() {
+        return $this->grade->feedback ?
+            format_text($this->grade->feedback, $this->grade->feedbackformat) :
+            '';
+    }
+
+    function is_disabled() {
+        return (
+            $this->grade->grade_item->is_overridable_item_feedback() and
+            !$this->grade->is_overridden()
+        );
+    }
+
+    function determine_format() {
+        return new quick_edit_text_attribute(
+            $this->get_name(),
+            $this->get_value(),
+            $this->is_disabled()
+        );
+    }
+}
+
+class quick_edit_override_ui extends quick_edit_grade_attribute_format implements be_checked {
+    var $name = 'override';
+
+    function is_checked() {
+        return $this->grade->is_overridden();
+    }
+
+    function determine_format() {
+        if (!$this->grade->grade_item->is_overridable_item()) {
+            return new quick_edit_empty_element();
+        }
+
+        return new quick_edit_checkbox_attribute(
+            $this->get_name(),
+            $this->is_checked()
+        );
+    }
+}
+
+class quick_edit_exclude_ui extends quick_edit_grade_attribute_format implements be_checked {
+    var $name = 'exclude';
+
+    function is_checked() {
+        return $this->grade->is_excluded();
+    }
+
+    function determine_format() {
+        return new quick_edit_checkbox_attribute(
+            $this->get_name(),
+            $this->is_checked()
+        );
+    }
+}
+
+class quick_edit_range_ui extends quick_edit_attribute_format {
+    function __construct($item) {
+        $this->item = $item;
+    }
+
+    function determine_format() {
+        $decimals = $this->item->get_decimals();
+
+        $min = format_float($this->item->grademin, $decimals);
+        $max = format_float($this->item->grademax, $decimals);
+
+        return new quick_edit_empty_element("$min - $max");
+    }
+}
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index 39e3e9b..ee7b4c6 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -1,10 +1,14 @@
 <?php
 
-class quick_edit_grade extends quick_edit_screen {
+class quick_edit_grade extends quick_edit_tablelike {
 
     private $requires_extra;
 
+    private $structure;
+
     public function init() {
+        global $DB;
+
         $params = array(
             'id' => $this->itemid,
             'courseid' => $this->courseid
@@ -14,24 +18,15 @@ class quick_edit_grade extends quick_edit_screen {
 
         $this->item = grade_item::fetch($params);
 
-        $this->users = get_role_users($roleids, $this->context, false, '',
+        $this->items = get_role_users($roleids, $this->context, false, '',
             'u.lastname, u.firstname', null, $this->groupid);
 
         $this->requires_extra = !$this->item->is_manual_item();
-    }
-
-    public function html() {
-        $table = new html_table();
-
-        $table->head = $this->headers();
 
-        $table->data = array();
-
-        foreach ($this->users as $user) {
-            $table->data[] = $this->format_line($user);
-        }
-
-        return html_writer::table($table);
+        $this->structure = new grade_structure();
+        $this->structure->modinfo = get_fast_modinfo(
+            $DB->get_record('course', array('id' => $this->courseid))
+        );
     }
 
     public function headers() {
@@ -46,21 +41,22 @@ class quick_edit_grade extends quick_edit_screen {
         return $this->additional_headers($headers);
     }
 
-    public function format_line($user) {
+    public function format_line($item) {
         global $OUTPUT;
 
-        $grade = $this->fetch_grade_or_default($this->item, $user);
+        $grade = $this->fetch_grade_or_default($this->item, $item);
 
-        $fullname = fullname($user);
+        $fullname = fullname($item);
 
-        $user->imagealt = $fullname;
+        $item->imagealt = $fullname;
 
         $line = array(
-            $OUTPUT->user_picture($user),
-            $this->format_link('user', $user->id, $fullname),
+            $OUTPUT->user_picture($item),
+            $this->format_link('user', $item->id, $fullname),
             $this->item_range(),
-            $this->format_grade($grade),
-            $this->format_feedback($grade)
+            $this->factory()->create('finalgrade')->format($grade) .
+            $this->structure->get_grade_analysis_icon($grade),
+            $this->factory()->create('feedback')->format($grade)
         );
 
         return $this->additional_cells($line, $grade);
@@ -68,7 +64,7 @@ class quick_edit_grade extends quick_edit_screen {
 
     public function additional_cells($line, $grade) {
         if ($this->requires_extra) {
-            $line[] = $this->format_override($grade);
+            $line[] = $this->factory()->create('override')->format($grade);
         }
 
         return $line;
@@ -84,7 +80,7 @@ class quick_edit_grade extends quick_edit_screen {
 
     public function item_range() {
         if (empty($this->range)) {
-            $this->range = $this->format_range($this->item);
+            $this->range = $this->factory()->create('range')->format($this->item);
         }
 
         return $this->range;
diff --git a/grade/report/quick_edit/screens/user/lib.php b/grade/report/quick_edit/screens/user/lib.php
index 3895cdc..da87092 100644
--- a/grade/report/quick_edit/screens/user/lib.php
+++ b/grade/report/quick_edit/screens/user/lib.php
@@ -1,6 +1,6 @@
 <?php
 
-class quick_edit_user extends quick_edit_screen {
+class quick_edit_user extends quick_edit_tablelike {
 
     private $categories = array();
 
@@ -15,23 +15,12 @@ class quick_edit_user extends quick_edit_screen {
 
         $filter_items = grade_report_quick_edit::only_items();
 
-        $this->grade_items = array_filter(grade_item::fetch_all($params), $filter_items);
+        $this->items= array_filter(grade_item::fetch_all($params), $filter_items);
 
         $this->structure = new grade_structure();
-    }
-
-    public function html() {
-        $table = new html_table();
-
-        $table->head = $this->headers();
-
-        $table->data = array();
-
-        foreach ($this->grade_items as $item) {
-            $table->data[] = $this->format_line($item);
-        }
-
-        return html_writer::table($table);
+        $this->structure->modinfo = get_fast_modinfo(
+            $DB->get_record('course', array('id' => $this->courseid))
+        );
     }
 
     public function headers() {
@@ -56,11 +45,12 @@ class quick_edit_user extends quick_edit_screen {
             $this->format_icon($item),
             $this->format_link('grade', $item->id, $item->itemname),
             $this->category($item)->get_name(),
-            $this->format_range($item),
-            $this->format_grade($grade),
-            $this->format_feedback($grade),
-            $this->format_override($grade),
-            $this->format_exclude($grade)
+            $this->factory()->create('range')->format($item),
+            $this->factory()->create('finalgrade')->format($grade) .
+            $this->structure->get_grade_analysis_icon($grade),
+            $this->factory()->create('feedback')->format($grade),
+            $this->factory()->create('override')->format($grade),
+            $this->factory()->create('exclude')->format($grade)
         );
     }
 
-- 
1.7.1


From 30b9e1dd08352aa36c91dc962e42f3d042c2925a Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 6 Feb 2012 15:08:35 -0600
Subject: Edit works

---
 grade/report/quick_edit/classes/datalib.php    |    4 +-
 grade/report/quick_edit/classes/lib.php        |   28 ++++++++++++++--
 grade/report/quick_edit/index.php              |   10 ++++++
 grade/report/quick_edit/lib.php                |    4 ++-
 grade/report/quick_edit/screens/grade/lib.php  |   30 +++++++++++++----
 grade/report/quick_edit/screens/select/lib.php |   42 +++++++++++++++---------
 grade/report/quick_edit/screens/user/lib.php   |   20 +++++++++--
 7 files changed, 106 insertions(+), 32 deletions(-)

diff --git a/grade/report/quick_edit/classes/datalib.php b/grade/report/quick_edit/classes/datalib.php
index 8930e30..3259feb 100644
--- a/grade/report/quick_edit/classes/datalib.php
+++ b/grade/report/quick_edit/classes/datalib.php
@@ -81,10 +81,10 @@ class quick_edit_grade_processor extends post_processor {
             if ($posted == -1) {
                 $finalgrade = null;
             } else {
-                $finalgrade = $posted;
+                $finalgrade = $value;
             }
         } else {
-            $finalgrade = unformat_float($posted);
+            $finalgrade = unformat_float($value);
         }
 
         $errorstr = '';
diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index ab76819..fc0777e 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -3,6 +3,14 @@
 require_once $CFG->dirroot . '/grade/report/quick_edit/classes/uilib.php';
 require_once $CFG->dirroot . '/grade/report/quick_edit/classes/datalib.php';
 
+interface selectable_items {
+    public function description();
+
+    public function options();
+
+    public function item_type();
+}
+
 abstract class quick_edit_screen {
     var $courseid;
 
@@ -19,7 +27,7 @@ abstract class quick_edit_screen {
 
         $this->context = get_context_instance(CONTEXT_COURSE, $this->courseid);
 
-        $this->init();
+        $this->init(empty($itemid));
     }
 
     public function format_link($screen, $itemid, $display = null) {
@@ -82,7 +90,7 @@ abstract class quick_edit_screen {
         return get_string('pluginname', 'gradereport_quick_edit');
     }
 
-    public abstract function init();
+    public abstract function init($self_item_is_empty = false);
 
     public abstract function html();
 
@@ -117,6 +125,20 @@ abstract class quick_edit_tablelike extends quick_edit_screen {
             $table->data[] = $this->format_line($item);
         }
 
-        return html_writer::table($table);
+        $button_attr = array('class' => 'quick_edit_buttons');
+        $button_html = implode(' ', $this->buttons());
+
+        $buttons = html_writer::tag('div', $button_html, $button_attr);
+
+        return html_writer::tag('form',
+            html_writer::table($table) . $buttons,
+            array('method' => 'POST')
+        );
+    }
+
+    public function buttons() {
+        $save = html_writer::empty_tag('input', array('type' => 'submit'));
+
+        return array($save);
     }
 }
diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index 3f11e5b..667873c 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -88,6 +88,16 @@ if ($reportname != $pluginname) {
 
 print_grade_page_head($course->id, 'report', 'quick_edit', $reportname);
 
+if ($data = data_submitted()) {
+    $warnings = $report->process_data($data);
+}
+
+if (!empty($warnings)) {
+    foreach ($warnings as $warning) {
+        echo $OUTPUT->notification($warning);
+    }
+}
+
 echo $report->output();
 
 echo $OUTPUT->footer();
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
index d136324..5ee857e 100755
--- a/grade/report/quick_edit/lib.php
+++ b/grade/report/quick_edit/lib.php
@@ -63,6 +63,7 @@ class grade_report_quick_edit extends grade_report {
     }
 
     function process_data($data) {
+        return $this->screen->processor()->handle($data);
     }
 
     function process_action($target, $action) {
@@ -81,6 +82,7 @@ class grade_report_quick_edit extends grade_report {
     }
 
     function output() {
-        return $this->screen->html();
+        global $OUTPUT;
+        return $OUTPUT->box($this->screen->html());
     }
 }
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index ee7b4c6..f16a1cd 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -1,12 +1,33 @@
 <?php
 
-class quick_edit_grade extends quick_edit_tablelike {
+class quick_edit_grade extends quick_edit_tablelike implements selectable_items {
 
     private $requires_extra;
 
     private $structure;
 
-    public function init() {
+    public function description() {
+        return get_string('users');
+    }
+
+    public function options() {
+        return array_map(function($user) { return fullname($user); }, $this->items);
+    }
+
+    public function item_type() {
+        return 'user';
+    }
+
+    public function init($self_item_is_empty = false) {
+        $roleids = explode(',', get_config('moodle', 'gradebookroles'));
+
+        $this->items = get_role_users($roleids, $this->context, false, '',
+                'u.lastname, u.firstname', null, $this->groupid);
+
+        if ($self_item_is_empty) {
+            return;
+        }
+
         global $DB;
 
         $params = array(
@@ -14,13 +35,8 @@ class quick_edit_grade extends quick_edit_tablelike {
             'courseid' => $this->courseid
         );
 
-        $roleids = explode(',', get_config('moodle', 'gradebookroles'));
-
         $this->item = grade_item::fetch($params);
 
-        $this->items = get_role_users($roleids, $this->context, false, '',
-            'u.lastname, u.firstname', null, $this->groupid);
-
         $this->requires_extra = !$this->item->is_manual_item();
 
         $this->structure = new grade_structure();
diff --git a/grade/report/quick_edit/screens/select/lib.php b/grade/report/quick_edit/screens/select/lib.php
index be87f26..ec2c258 100644
--- a/grade/report/quick_edit/screens/select/lib.php
+++ b/grade/report/quick_edit/screens/select/lib.php
@@ -2,33 +2,43 @@
 
 // TODO: custom form with group selector
 class quick_edit_select extends quick_edit_screen {
-    public function init() {
+    public function init($self_item_is_empty = false) {
         global $DB;
 
-        $params = array('courseid' => $this->courseid);
-
-        $filter_items = grade_report_quick_edit::only_items();
-
-        $this->grade_items = array_filter(grade_item::fetch_all($params), $filter_items);
-
         $this->item = $DB->get_record('course', array('id' => $this->courseid));
     }
 
     public function html() {
         global $OUTPUT;
 
-        $map = function($item) { return $item->itemname; };
+        $html = '';
+
+        $types = grade_report_quick_edit::valid_screens();
+
+        foreach ($types as $type) {
+            if ($type == 'select') continue;
+
+            $class = grade_report_quick_edit::classname($type);
+
+            $screen = new $class($this->courseid, null, $this->groupid);
+
+            if (!method_exists($screen, 'options')) {
+                continue;
+            }
+
+            $params = array(
+                'id' => $this->courseid,
+                'item' => $screen->item_type(),
+                'group' => $this->groupid
+            );
 
-        $grade_options = array_map($map, $this->grade_items);
+            $url = new moodle_url('/grade/report/quick_edit/index.php', $params);
 
-        $params = array(
-            'id' => $this->courseid,
-            'item' => 'grade',
-            'group' => $this->groupid
-        );
+            $html .= $OUTPUT->heading($screen->description());
 
-        $url = new moodle_url('/grade/report/quick_edit/index.php', $params);
+            $html .= $OUTPUT->single_select($url, 'itemid', $screen->options());
+        }
 
-        echo $OUTPUT->single_select($url, 'itemid', $grade_options, $this->itemid);
+        return $html;
     }
 }
diff --git a/grade/report/quick_edit/screens/user/lib.php b/grade/report/quick_edit/screens/user/lib.php
index da87092..df24974 100644
--- a/grade/report/quick_edit/screens/user/lib.php
+++ b/grade/report/quick_edit/screens/user/lib.php
@@ -1,15 +1,29 @@
 <?php
 
-class quick_edit_user extends quick_edit_tablelike {
+class quick_edit_user extends quick_edit_tablelike implements selectable_items {
 
     private $categories = array();
 
     private $structure;
 
-    public function init() {
+    public function description() {
+        return get_string('gradeitems', 'grades');;
+    }
+
+    public function options() {
+        return array_map(function($item) { return $item->get_name(); }, $this->items);
+    }
+
+    public function item_type() {
+        return 'grade';
+    }
+
+    public function init($self_item_is_empty = false) {
         global $DB;
 
-        $this->user = $DB->get_record('user', array('id' => $this->itemid));
+        if (!$self_item_is_empty) {
+            $this->user = $DB->get_record('user', array('id' => $this->itemid));
+        }
 
         $params = array('courseid' => $this->courseid);
 
-- 
1.7.1


From d4da3d8f05c62cb23bee3b7ae0953f6f13ae30ee Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Mon, 6 Feb 2012 15:30:16 -0600
Subject: Adding javascript

---
 grade/report/quick_edit/classes/lib.php  |   12 ++++++++++++
 grade/report/quick_edit/js/quick_edit.js |    5 +++++
 2 files changed, 17 insertions(+), 0 deletions(-)
 create mode 100644 grade/report/quick_edit/js/quick_edit.js

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index fc0777e..36924dc 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -94,6 +94,18 @@ abstract class quick_edit_screen {
 
     public abstract function html();
 
+    public function js() {
+        global $PAGE;
+
+        $module = array(
+            'name' => 'gradereport_quick_edit',
+            'fullpath' => '/grade/report/quick_edit/js/quick_edit.js',
+            'requires' => array('base', 'dom', 'event', 'io-base');
+        );
+
+        $PAGE->requires->js_init_call('M.gradereport_quick_edit.init', array(), false, $module);
+    }
+
     public function factory() {
         if (empty($this->__factory)) {
             $this->__factory = new quick_edit_grade_ui_factory();
diff --git a/grade/report/quick_edit/js/quick_edit.js b/grade/report/quick_edit/js/quick_edit.js
new file mode 100644
index 0000000..da16cc6
--- /dev/null
+++ b/grade/report/quick_edit/js/quick_edit.js
@@ -0,0 +1,5 @@
+M.gradereport_quick_edit = {};
+
+M.gradereport_quick_edit.init = function(Y) {
+    alert("hey");
+};
-- 
1.7.1


From 8e9a66cd2dc71894716750dcbf14aa321b48e678 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Tue, 7 Feb 2012 11:02:10 -0600
Subject: Making use of javascript.

---
 grade/report/quick_edit/classes/lib.php  |    6 ++--
 grade/report/quick_edit/js/quick_edit.js |   41 +++++++++++++++++++++++++++++-
 grade/report/quick_edit/lib.php          |    3 ++
 3 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index 36924dc..d0d5ea0 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -69,11 +69,11 @@ abstract class quick_edit_screen {
         $attrs = array('href' => '#');
 
         $all = html_writer::tag('a', get_string('all'), $attrs + array(
-            'class' => 'include_all ' . $key
+            'class' => 'include all ' . $key
         ));
 
         $none = html_writer::tag('a', get_string('none'), $attrs + array(
-            'class' => 'include_none ' . $key
+            'class' => 'include none ' . $key
         ));
 
         return html_writer::tag('span', "$all / $none", array(
@@ -100,7 +100,7 @@ abstract class quick_edit_screen {
         $module = array(
             'name' => 'gradereport_quick_edit',
             'fullpath' => '/grade/report/quick_edit/js/quick_edit.js',
-            'requires' => array('base', 'dom', 'event', 'io-base');
+            'requires' => array('base', 'dom', 'event', 'io-base')
         );
 
         $PAGE->requires->js_init_call('M.gradereport_quick_edit.init', array(), false, $module);
diff --git a/grade/report/quick_edit/js/quick_edit.js b/grade/report/quick_edit/js/quick_edit.js
index da16cc6..7f115d7 100644
--- a/grade/report/quick_edit/js/quick_edit.js
+++ b/grade/report/quick_edit/js/quick_edit.js
@@ -1,5 +1,44 @@
 M.gradereport_quick_edit = {};
 
 M.gradereport_quick_edit.init = function(Y) {
-    alert("hey");
+    var toggle = function(check) {
+        return function(input) {
+            if (check) {
+                input.setAttribute('checked', 'CHECKED');
+            } else {
+                input.removeAttribute('checked');
+            }
+        };
+    };
+
+    // Made toggle links
+    Y.all('.include').each(function(link) {
+        var type = link.getAttribute('class').split(" ")[2];
+
+        link.on('click', function() {
+            Y.all('input[name^=' + type + ']').each(toggle(link.hasClass('all')));
+            return false;
+        });
+    });
+
+    // Override Toggle
+    Y.all('input[name^=override_]').each(function(input) {
+        input.on('change', function() {
+            var checked = input.getDOMNode().checked;
+            var names = input.getAttribute('name').split("_");
+
+            var itemid = names[1];
+            var userid = names[2];
+
+            var interest = '_' + itemid + '_' + userid;
+
+            Y.all('input[name$=' + interest + ']').filter('input[type=text]').each(function(text) {
+                if (!checked) {
+                    text.setAttribute('disabled', 'DISABLED');
+                } else {
+                    text.removeAttribute('disabled');
+                }
+            });
+        });
+    });
 };
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
index 5ee857e..5076cbd 100755
--- a/grade/report/quick_edit/lib.php
+++ b/grade/report/quick_edit/lib.php
@@ -79,6 +79,9 @@ class grade_report_quick_edit extends grade_report {
         $class = self::classname($itemtype);
 
         $this->screen = new $class($courseid, $itemid, $groupid);
+
+        // Load custom or predifined js
+        $this->screen->js();
     }
 
     function output() {
-- 
1.7.1


From 440433c3e96918c8e1a89416cb93abd9a8a45d46 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 8 Feb 2012 09:51:37 -0600
Subject: Cleaned up js a little more

---
 grade/report/quick_edit/classes/lib.php  |    2 +-
 grade/report/quick_edit/js/quick_edit.js |   25 +++++++++----------------
 2 files changed, 10 insertions(+), 17 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index d0d5ea0..2172da0 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -100,7 +100,7 @@ abstract class quick_edit_screen {
         $module = array(
             'name' => 'gradereport_quick_edit',
             'fullpath' => '/grade/report/quick_edit/js/quick_edit.js',
-            'requires' => array('base', 'dom', 'event', 'io-base')
+            'requires' => array('base', 'dom', 'event', 'event-simulate', 'io-base')
         );
 
         $PAGE->requires->js_init_call('M.gradereport_quick_edit.init', array(), false, $module);
diff --git a/grade/report/quick_edit/js/quick_edit.js b/grade/report/quick_edit/js/quick_edit.js
index 7f115d7..f7dc442 100644
--- a/grade/report/quick_edit/js/quick_edit.js
+++ b/grade/report/quick_edit/js/quick_edit.js
@@ -1,20 +1,17 @@
 M.gradereport_quick_edit = {};
 
 M.gradereport_quick_edit.init = function(Y) {
-    var toggle = function(check) {
-        return function(input) {
-            if (check) {
-                input.setAttribute('checked', 'CHECKED');
-            } else {
-                input.removeAttribute('checked');
-            }
-        };
-    };
-
-    // Made toggle links
+    // Make toggle links
     Y.all('.include').each(function(link) {
         var type = link.getAttribute('class').split(" ")[2];
 
+        var toggle = function(checked) {
+            return function(input) {
+                input.getDOMNode().checked = checked;
+                Y.Event.simulate(input.getDOMNode(), 'change');
+            };
+        };
+
         link.on('click', function() {
             Y.all('input[name^=' + type + ']').each(toggle(link.hasClass('all')));
             return false;
@@ -33,11 +30,7 @@ M.gradereport_quick_edit.init = function(Y) {
             var interest = '_' + itemid + '_' + userid;
 
             Y.all('input[name$=' + interest + ']').filter('input[type=text]').each(function(text) {
-                if (!checked) {
-                    text.setAttribute('disabled', 'DISABLED');
-                } else {
-                    text.removeAttribute('disabled');
-                }
+                text.getDOMNode().disabled = !checked;
             });
         });
     });
-- 
1.7.1


From 0cc60674798ea7cc6472917cc9440de26f599b6d Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 8 Feb 2012 12:47:30 -0600
Subject: Moved process into screen... element handles post

---
 grade/report/quick_edit/classes/datalib.php    |  163 ------------------------
 grade/report/quick_edit/classes/lib.php        |   91 ++++++++++++-
 grade/report/quick_edit/classes/uilib.php      |  122 ++++++++++++++++++
 grade/report/quick_edit/index.php              |   10 +-
 grade/report/quick_edit/lib.php                |    2 +-
 grade/report/quick_edit/screens/grade/lib.php  |   29 ++--
 grade/report/quick_edit/screens/select/lib.php |    5 +-
 grade/report/quick_edit/screens/user/lib.php   |   21 ++--
 8 files changed, 240 insertions(+), 203 deletions(-)
 delete mode 100644 grade/report/quick_edit/classes/datalib.php

diff --git a/grade/report/quick_edit/classes/datalib.php b/grade/report/quick_edit/classes/datalib.php
deleted file mode 100644
index 3259feb..0000000
--- a/grade/report/quick_edit/classes/datalib.php
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-
-abstract class post_processor {
-    function __construct($courseid) {
-        $this->courseid = $courseid;
-    }
-
-    abstract function handle($data);
-}
-
-class quick_edit_grade_processor extends post_processor {
-    function get_fields() {
-        return array(
-            'finalgrade', 'feedback', 'override', 'exclude'
-        );
-    }
-
-    function handle($data) {
-        foreach ($data as $varname => $throw) {
-            if (preg_match("/(\w+)_(\d+)_(\d+)/", $varname, $matches)) {
-                $itemid = $matches[2];
-                $userid = $matches[3];
-            } else {
-                continue;
-            }
-
-            $grade_item = grade_item::fetch(array(
-                'id' => $itemid, 'courseid' => $this->courseid
-            ));
-
-            if (!$grade_item) {
-                continue;
-            }
-
-            $fields = $this->get_fields();
-
-            $warnings = array();
-            foreach ($fields as $field) {
-
-                $name = "{$field}_{$itemid}_{$userid}";
-                $oldname = "old$name";
-
-                // Probably not supported
-                if (empty($data->$name) and empty($data->$oldname)) {
-                    continue;
-                }
-
-                // Probably a checkbox
-                if (!isset($data->$name) and isset($data->$oldname)) {
-                    $data->$name = 0;
-                }
-
-                $posted = $data->$name;
-                $oldvalue = $data->$oldname;
-
-                // Same value; skip
-                if ($oldvalue == $posted) {
-                    continue;
-                }
-
-                $func = 'set_' . $field;
-
-                $msg = $this->{$func}($grade_item, $userid, $posted);
-
-                // Optional type
-                if (!empty($msg)) {
-                    $warnings[] = $msg;
-                }
-            }
-        }
-
-        return $warnings;
-    }
-
-    function set_finalgrade($grade_item, $userid, $value) {
-        global $DB;
-
-        $feedback = false;
-        $feedbackformat = false;
-        if ($grade_item->gradetype == GRADE_TYPE_SCALE) {
-            if ($posted == -1) {
-                $finalgrade = null;
-            } else {
-                $finalgrade = $value;
-            }
-        } else {
-            $finalgrade = unformat_float($value);
-        }
-
-        $errorstr = '';
-        if (is_null($finalgrade)) {
-            // ok
-        } else {
-            $bounded = $grade_item->bounded_grade($finalgrade);
-            if ($bounded > $finalgrade) {
-                $errorstr = 'lessthanmin';
-            } else if ($bounded < $finalgrade) {
-                $errorstr = 'morethanmax';
-            }
-        }
-
-        if ($errorstr) {
-            $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
-            $gradestr = new stdClass;
-            $gradestr->username = fullname($user);
-            $gradestr->itemname = $grade_item->get_name();
-
-            return get_string($errorstr, 'grades', $gradestr);
-        }
-
-        $grade_item->update_final_grade($userid, $finalgrade, 'quick_edit', $feedback, FORMAT_MOODLE);
-        return false;
-    }
-
-    function set_feedback($grade_item, $userid, $value) {
-        $finalgrade = false;
-        $trimmed = trim($value);
-        if (empty($trimmed)) {
-            $feedback = NULL;
-        } else {
-            $feedback = $value;
-        }
-
-        $grade_item->update_final_grade($userid, $finalgrade, 'quick_edit', $feedback, FORMAT_MOODLE);
-    }
-
-    function set_override($grade_item, $userid, $value) {
-        $grade = grade_grade::fetch(array(
-            'itemid' => $grade_item->id, 'userid' => $userid
-        ));
-
-        if (empty($grade)) {
-            return false;
-        }
-
-        $state = $value == 0 ? false : true;
-
-        return !$grade->set_overridden($state);
-    }
-
-    function set_exclude($grade_item, $userid, $value) {
-        $grade_params = array(
-            'itemid' => $grade_item->id, 'userid' => $userid
-        );
-
-        $grade = grade_grade::fetch($grade_params);
-
-        if (empty($grade)) {
-            if (empty($value)) {
-                return false;
-            }
-
-            // Fill in arbitrary grade to be excluded
-            $grade_item->update_final_grade($userid, null, 'quick_edit', null, FORMAT_MOODLE);
-
-            $grade = grade_grade::fetch($grade_params);
-        }
-
-        $state = $value == 0 ? false : true;
-
-        return !$grade->set_excluded($state);
-    }
-}
diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index 2172da0..1918612 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -1,7 +1,6 @@
 <?php
 
 require_once $CFG->dirroot . '/grade/report/quick_edit/classes/uilib.php';
-require_once $CFG->dirroot . '/grade/report/quick_edit/classes/datalib.php';
 
 interface selectable_items {
     public function description();
@@ -45,15 +44,15 @@ abstract class quick_edit_screen {
         }
     }
 
-    public function fetch_grade_or_default($item, $user) {
+    public function fetch_grade_or_default($item, $userid) {
         $grade = grade_grade::fetch(array(
-            'itemid' => $item->id, 'userid' => $user->id
+            'itemid' => $item->id, 'userid' => $userid
         ));
 
         if (!$grade) {
             $default = new stdClass;
 
-            $default->userid = $user->id;
+            $default->userid = $userid;
             $default->itemid = $item->id;
             $default->feedback = '';
 
@@ -114,8 +113,70 @@ abstract class quick_edit_screen {
         return $this->__factory;
     }
 
-    public function processor() {
-        return new quick_edit_grade_processor($this->courseid);
+    public function process($data) {
+        $warnings = array();
+
+        foreach ($data as $varname => $throw) {
+            if (preg_match("/(\w+)_(\d+)_(\d+)/", $varname, $matches)) {
+                $itemid = $matches[2];
+                $userid = $matches[3];
+            } else {
+                continue;
+            }
+
+            $fields = $this->definition();
+
+            if (!in_array($matches[1], $fields)) {
+                continue;
+            }
+
+            $grade_item = grade_item::fetch(array(
+                'id' => $itemid, 'courseid' => $this->courseid
+            ));
+
+            if (!$grade_item) {
+                continue;
+            }
+
+            $grade = $this->fetch_grade_or_default($grade_item, $userid);
+
+            $element = $this->factory()->create($matches[1])->format($grade);
+
+            $name = $element->get_name();
+            $oldname = "old$name";
+
+            $posted = $data->$name;
+            $oldvalue = $data->$oldname;
+
+            // Probably not supported
+            if (empty($data->$name) and empty($data->$oldname)) {
+                continue;
+            }
+
+            $format = $element->determine_format();
+
+            if ($format->is_textbox() and trim($data->$name) === '') {
+                $data->$name = null;
+            }
+
+            // Same value; skip
+            if ($oldvalue == $posted) {
+                continue;
+            }
+
+            $msg = $element->set($posted);
+
+            // Optional type
+            if (!empty($msg)) {
+                $warnings[] = $msg;
+            }
+        }
+
+        return $warnings;
+    }
+
+    public function definition() {
+        return array();
     }
 }
 
@@ -126,6 +187,20 @@ abstract class quick_edit_tablelike extends quick_edit_screen {
 
     public abstract function format_line($item);
 
+    public function format_definition($line, $grade) {
+        foreach ($this->definition() as $field) {
+            $html = $this->factory()->create($field)->format($grade);
+
+            if ($field == 'finalgrade') {
+                $html .= $this->structure->get_grade_analysis_icon($grade);
+            }
+
+            $line[] = $html;
+        }
+
+        return $line;
+    }
+
     public function html() {
         $table = new html_table();
 
@@ -149,7 +224,9 @@ abstract class quick_edit_tablelike extends quick_edit_screen {
     }
 
     public function buttons() {
-        $save = html_writer::empty_tag('input', array('type' => 'submit'));
+        $save = html_writer::empty_tag('input', array(
+            'type' => 'submit', 'value' => get_string('update')
+        ));
 
         return array($save);
     }
diff --git a/grade/report/quick_edit/classes/uilib.php b/grade/report/quick_edit/classes/uilib.php
index e36a0dc..8dd1cb4 100644
--- a/grade/report/quick_edit/classes/uilib.php
+++ b/grade/report/quick_edit/classes/uilib.php
@@ -33,6 +33,18 @@ abstract class quick_edit_ui_element {
         $this->value = $value;
     }
 
+    function is_checkbox() {
+        return false;
+    }
+
+    function is_textbox() {
+        return false;
+    }
+
+    function is_dropdown() {
+        return false;
+    }
+
     abstract function html();
 }
 
@@ -58,6 +70,10 @@ class quick_edit_text_attribute extends quick_edit_ui_element {
         parent::__construct($name, $value);
     }
 
+    function is_textbox() {
+        return true;
+    }
+
     function html() {
         $attributes = array(
             'type' => 'text',
@@ -90,6 +106,10 @@ class quick_edit_checkbox_attribute extends quick_edit_ui_element {
         parent::__construct($name, 1);
     }
 
+    function is_checkbox() {
+        return true;
+    }
+
     function html() {
         $attributes = array(
             'type' => 'checkbox',
@@ -97,6 +117,12 @@ class quick_edit_checkbox_attribute extends quick_edit_ui_element {
             'value' => 1
         );
 
+        $alt = array(
+            'type' => 'hidden',
+            'name' => $this->name,
+            'value' => 0
+        );
+
         $hidden = array(
             'type' => 'hidden',
             'name' => 'old' . $this->name
@@ -108,6 +134,7 @@ class quick_edit_checkbox_attribute extends quick_edit_ui_element {
         }
 
         return (
+            html_writer::empty_tag('input', $alt) .
             html_writer::empty_tag('input', $attributes) .
             html_writer::empty_tag('input', $hidden)
         );
@@ -132,6 +159,8 @@ abstract class quick_edit_grade_attribute_format extends quick_edit_attribute_fo
     function get_name() {
         return "{$this->name}_{$this->grade->itemid}_{$this->grade->userid}";
     }
+
+    public abstract function set($value);
 }
 
 interface unique_name {
@@ -174,6 +203,49 @@ class quick_edit_finalgrade_ui extends quick_edit_grade_attribute_format impleme
             $this->is_disabled()
         );
     }
+
+    function set($value) {
+        global $DB;
+
+        $userid = $this->grade->userid;
+        $grade_item = $this->grade->grade_item;
+
+        $feedback = false;
+        $feedbackformat = false;
+        if ($grade_item->gradetype == GRADE_TYPE_SCALE) {
+            if ($value == -1) {
+                $finalgrade = null;
+            } else {
+                $finalgrade = $value;
+            }
+        } else {
+            $finalgrade = unformat_float($value);
+        }
+
+        $errorstr = '';
+        if (is_null($finalgrade)) {
+            // ok
+        } else {
+            $bounded = $grade_item->bounded_grade($finalgrade);
+            if ($bounded > $finalgrade) {
+                $errorstr = 'lessthanmin';
+            } else if ($bounded < $finalgrade) {
+                $errorstr = 'morethanmax';
+            }
+        }
+
+        if ($errorstr) {
+            $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
+            $gradestr = new stdClass;
+            $gradestr->username = fullname($user);
+            $gradestr->itemname = $this->grade->grade_item->get_name();
+
+            $errorstr = get_string($errorstr, 'grades', $gradestr);
+        }
+
+        $grade_item->update_final_grade($userid, $finalgrade, 'quick_edit', $feedback, FORMAT_MOODLE);
+        return $errorstr;
+    }
 }
 
 class quick_edit_feedback_ui extends quick_edit_grade_attribute_format implements unique_value, be_disabled {
@@ -200,6 +272,22 @@ class quick_edit_feedback_ui extends quick_edit_grade_attribute_format implement
             $this->is_disabled()
         );
     }
+
+    function set($value) {
+        $finalgrade = false;
+        $trimmed = trim($value);
+        if (empty($trimmed)) {
+            $feedback = NULL;
+        } else {
+            $feedback = $value;
+        }
+
+        $this->grade->grade_item->update_final_grade(
+            $this->grade->userid, $finalgrade, 'quick_edit',
+            $feedback, FORMAT_MOODLE
+        );
+        return false;
+    }
 }
 
 class quick_edit_override_ui extends quick_edit_grade_attribute_format implements be_checked {
@@ -219,6 +307,18 @@ class quick_edit_override_ui extends quick_edit_grade_attribute_format implement
             $this->is_checked()
         );
     }
+
+    function set($value) {
+        if (empty($this->grade->id)) {
+            return false;
+        }
+
+        $state = $value == 0 ? false : true;
+
+        $this->grade->set_overridden($state);
+        $this->grade->grade_item->get_parent_category()->force_regrading();
+        return false;
+    }
 }
 
 class quick_edit_exclude_ui extends quick_edit_grade_attribute_format implements be_checked {
@@ -234,6 +334,28 @@ class quick_edit_exclude_ui extends quick_edit_grade_attribute_format implements
             $this->is_checked()
         );
     }
+
+    function set($value) {
+        if (empty($this->grade->id)) {
+            if (empty($value)) {
+                return false;
+            }
+
+            // Fill in arbitrary grade to be excluded
+            $this->grade->grade_item->update_final_grade(
+                $this->grade->userid, 0, 'quick_edit', null, FORMAT_MOODLE
+            );
+
+            $this->grade = grade_grade::fetch($grade_params);
+        }
+
+        $state = $value == 0 ? false : true;
+
+        $this->grade->set_excluded($state);
+
+        $this->grade->grade_item->get_parent_category()->force_regrading();
+        return false;
+    }
 }
 
 class quick_edit_range_ui extends quick_edit_attribute_format {
diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index 667873c..034406a 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -90,11 +90,13 @@ print_grade_page_head($course->id, 'report', 'quick_edit', $reportname);
 
 if ($data = data_submitted()) {
     $warnings = $report->process_data($data);
-}
 
-if (!empty($warnings)) {
-    foreach ($warnings as $warning) {
-        echo $OUTPUT->notification($warning);
+    if (empty($warnings)) {
+        echo $OUTPUT->notification(get_string('changessaved'), 'notifysuccess');
+    } else {
+        foreach ($warnings as $warning) {
+            echo $OUTPUT->notification($warning);
+        }
     }
 }
 
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
index 5076cbd..cb21d6c 100755
--- a/grade/report/quick_edit/lib.php
+++ b/grade/report/quick_edit/lib.php
@@ -63,7 +63,7 @@ class grade_report_quick_edit extends grade_report {
     }
 
     function process_data($data) {
-        return $this->screen->processor()->handle($data);
+        return $this->screen->process($data);
     }
 
     function process_action($target, $action) {
diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index f16a1cd..a4f9ff1 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -4,7 +4,7 @@ class quick_edit_grade extends quick_edit_tablelike implements selectable_items
 
     private $requires_extra;
 
-    private $structure;
+    var $structure;
 
     public function description() {
         return get_string('users');
@@ -18,6 +18,16 @@ class quick_edit_grade extends quick_edit_tablelike implements selectable_items
         return 'user';
     }
 
+    public function definition() {
+        $def = array('finalgrade', 'feedback');
+
+        if ($this->requires_extra) {
+            $def[] = 'override';
+        }
+
+        return $def;
+    }
+
     public function init($self_item_is_empty = false) {
         $roleids = explode(',', get_config('moodle', 'gradebookroles'));
 
@@ -60,7 +70,7 @@ class quick_edit_grade extends quick_edit_tablelike implements selectable_items
     public function format_line($item) {
         global $OUTPUT;
 
-        $grade = $this->fetch_grade_or_default($this->item, $item);
+        $grade = $this->fetch_grade_or_default($this->item, $item->id);
 
         $fullname = fullname($item);
 
@@ -69,21 +79,10 @@ class quick_edit_grade extends quick_edit_tablelike implements selectable_items
         $line = array(
             $OUTPUT->user_picture($item),
             $this->format_link('user', $item->id, $fullname),
-            $this->item_range(),
-            $this->factory()->create('finalgrade')->format($grade) .
-            $this->structure->get_grade_analysis_icon($grade),
-            $this->factory()->create('feedback')->format($grade)
+            $this->item_range()
         );
 
-        return $this->additional_cells($line, $grade);
-    }
-
-    public function additional_cells($line, $grade) {
-        if ($this->requires_extra) {
-            $line[] = $this->factory()->create('override')->format($grade);
-        }
-
-        return $line;
+        return $this->format_definition($line, $grade);
     }
 
     public function additional_headers($headers) {
diff --git a/grade/report/quick_edit/screens/select/lib.php b/grade/report/quick_edit/screens/select/lib.php
index ec2c258..cb2c3f8 100644
--- a/grade/report/quick_edit/screens/select/lib.php
+++ b/grade/report/quick_edit/screens/select/lib.php
@@ -1,6 +1,5 @@
 <?php
 
-// TODO: custom form with group selector
 class quick_edit_select extends quick_edit_screen {
     public function init($self_item_is_empty = false) {
         global $DB;
@@ -16,13 +15,11 @@ class quick_edit_select extends quick_edit_screen {
         $types = grade_report_quick_edit::valid_screens();
 
         foreach ($types as $type) {
-            if ($type == 'select') continue;
-
             $class = grade_report_quick_edit::classname($type);
 
             $screen = new $class($this->courseid, null, $this->groupid);
 
-            if (!method_exists($screen, 'options')) {
+            if (!$screen instanceof selectable_items) {
                 continue;
             }
 
diff --git a/grade/report/quick_edit/screens/user/lib.php b/grade/report/quick_edit/screens/user/lib.php
index df24974..2da67e0 100644
--- a/grade/report/quick_edit/screens/user/lib.php
+++ b/grade/report/quick_edit/screens/user/lib.php
@@ -4,7 +4,7 @@ class quick_edit_user extends quick_edit_tablelike implements selectable_items {
 
     private $categories = array();
 
-    private $structure;
+    var $structure;
 
     public function description() {
         return get_string('gradeitems', 'grades');;
@@ -18,6 +18,12 @@ class quick_edit_user extends quick_edit_tablelike implements selectable_items {
         return 'grade';
     }
 
+    public function definition() {
+        return array(
+            'finalgrade', 'feedback', 'override', 'exclude'
+        );
+    }
+
     public function init($self_item_is_empty = false) {
         global $DB;
 
@@ -53,19 +59,16 @@ class quick_edit_user extends quick_edit_tablelike implements selectable_items {
     public function format_line($item) {
         global $OUTPUT;
 
-        $grade = $this->fetch_grade_or_default($item, $this->user);
+        $grade = $this->fetch_grade_or_default($item, $this->user->id);
 
-        return array(
+        $line = array(
             $this->format_icon($item),
             $this->format_link('grade', $item->id, $item->itemname),
             $this->category($item)->get_name(),
-            $this->factory()->create('range')->format($item),
-            $this->factory()->create('finalgrade')->format($grade) .
-            $this->structure->get_grade_analysis_icon($grade),
-            $this->factory()->create('feedback')->format($grade),
-            $this->factory()->create('override')->format($grade),
-            $this->factory()->create('exclude')->format($grade)
+            $this->factory()->create('range')->format($item)
         );
+
+        return $this->format_definition($line, $grade);
     }
 
     private function format_icon($item) {
-- 
1.7.1


From 2affeee9b99294152ab88abb931622e654958dfb Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 8 Feb 2012 13:59:40 -0600
Subject: Group selector, adheres to course groupmode

---
 grade/report/quick_edit/classes/lib.php      |    4 ++++
 grade/report/quick_edit/index.php            |    4 ++++
 grade/report/quick_edit/lib.php              |   13 +++++++++++++
 grade/report/quick_edit/screens/user/lib.php |    4 ++++
 4 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index 1918612..c5f0d9b 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -178,6 +178,10 @@ abstract class quick_edit_screen {
     public function definition() {
         return array();
     }
+
+    public function display_group_selector() {
+        return true;
+    }
 }
 
 abstract class quick_edit_tablelike extends quick_edit_screen {
diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index 034406a..1d1719e 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -88,6 +88,10 @@ if ($reportname != $pluginname) {
 
 print_grade_page_head($course->id, 'report', 'quick_edit', $reportname);
 
+if ($report->screen->display_group_selector()) {
+    echo $report->group_selector;
+}
+
 if ($data = data_submitted()) {
     $warnings = $report->process_data($data);
 
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
index cb21d6c..22d0aa0 100755
--- a/grade/report/quick_edit/lib.php
+++ b/grade/report/quick_edit/lib.php
@@ -82,6 +82,19 @@ class grade_report_quick_edit extends grade_report {
 
         // Load custom or predifined js
         $this->screen->js();
+
+        $base = '/grade/report/quick_edit/index.php';
+
+        $id_params = array('id' => $courseid);
+
+        $this->baseurl = new moodle_url($base, $id_params);
+
+        $this->pbarurl = new moodle_url($base, $id_params + array(
+            'item' => $itemtype,
+            'itemid' => $itemid
+        ));
+
+        $this->setup_groups();
     }
 
     function output() {
diff --git a/grade/report/quick_edit/screens/user/lib.php b/grade/report/quick_edit/screens/user/lib.php
index 2da67e0..aa333f8 100644
--- a/grade/report/quick_edit/screens/user/lib.php
+++ b/grade/report/quick_edit/screens/user/lib.php
@@ -24,6 +24,10 @@ class quick_edit_user extends quick_edit_tablelike implements selectable_items {
         );
     }
 
+    public function display_group_selector() {
+        return false;
+    }
+
     public function init($self_item_is_empty = false) {
         global $DB;
 
-- 
1.7.1


From 54489f33be2ce5129bc82146d8f26bcd9fff15f1 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 8 Feb 2012 14:43:04 -0600
Subject: Profile report integration, because why not

---
 grade/report/quick_edit/index.php |   10 ++++++++--
 grade/report/quick_edit/lib.php   |   32 ++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index 1d1719e..ed8da87 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -28,10 +28,16 @@ require_once $CFG->dirroot.'/grade/lib.php';
 require_once $CFG->dirroot.'/grade/report/quick_edit/lib.php';
 
 $courseid = required_param('id', PARAM_INT);
-$itemtype = optional_param('item', 'select', PARAM_TEXT);
-$itemid = optional_param('itemid', null, PARAM_INT);
 $groupid  = optional_param('group', null, PARAM_INT);
 
+// Making this work with profile reports
+$userid = optional_param('userid', null, PARAM_INT);
+
+$default_type = $userid ? 'user' : 'select';
+
+$itemid = optional_param('itemid', $userid, PARAM_INT);
+$itemtype = optional_param('item', $default_type, PARAM_TEXT);
+
 $PAGE->set_url(new moodle_url('/grade/report/quick_edit/index.php', array(
     'id' => $courseid,
     'item' => $itemtype,
diff --git a/grade/report/quick_edit/lib.php b/grade/report/quick_edit/lib.php
index 22d0aa0..7738af3 100755
--- a/grade/report/quick_edit/lib.php
+++ b/grade/report/quick_edit/lib.php
@@ -102,3 +102,35 @@ class grade_report_quick_edit extends grade_report {
         return $OUTPUT->box($this->screen->html());
     }
 }
+
+function grade_report_quick_edit_profilereport($course, $user) {
+    global $CFG, $OUTPUT;
+
+    if (!function_exists('grade_report_user_profilereport')) {
+        require_once $CFG->dirroot . '/grade/report/user/lib.php';
+    }
+
+    $context = get_context_instance(CONTEXT_COURSE, $course->id);
+
+    $can_use = (
+        has_capability('gradereport/quick_edit:view', $context) and
+        has_capability('moodle/grade:viewall', $context) and
+        has_capability('moodle/grade:edit', $context)
+    );
+
+    if (!$can_use) {
+        grade_report_user_profilereport($course, $user);
+    } else {
+        $gpr = new grade_plugin_return(array(
+            'type' => 'report',
+            'plugin' => 'quick_edit',
+            'courseid' => $course->id,
+            'userid' => $user->id
+        ));
+
+        $report = new grade_report_quick_edit($course->id, $gpr, $context, 'user', $user->id);
+
+        echo $OUTPUT->heading($report->screen->heading());
+        echo $report->output();
+    }
+}
-- 
1.7.1


From eccce8ad25cd3dde7b447288572c293928f10402 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 8 Feb 2012 15:28:43 -0600
Subject: Report name consistency

---
 .../quick_edit/lang/en/gradereport_quick_edit.php  |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
index a157bf7..6d893ca 100755
--- a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
+++ b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
@@ -23,7 +23,7 @@
 ///////////////////////////////////////////////////////////////////////////
 
 // General Strings
-$string['pluginname'] = 'Quick Edit';
+$string['pluginname'] = 'Quick Edit report';
 $string['quick_edit:view'] = 'View the '.$string['pluginname'].' report';
 
 $string['exclude'] = 'Exclude';
-- 
1.7.1


From c88a56a69d5eb2dd17bd8ecc443d8ea500c6fd8b Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 10 Feb 2012 10:06:39 -0600
Subject: Corrects course navigation.

---
 grade/report/quick_edit/index.php                  |   14 +++++++-------
 .../quick_edit/lang/en/gradereport_quick_edit.php  |    2 +-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/grade/report/quick_edit/index.php b/grade/report/quick_edit/index.php
index ed8da87..f34c5ef 100755
--- a/grade/report/quick_edit/index.php
+++ b/grade/report/quick_edit/index.php
@@ -38,15 +38,10 @@ $default_type = $userid ? 'user' : 'select';
 $itemid = optional_param('itemid', $userid, PARAM_INT);
 $itemtype = optional_param('item', $default_type, PARAM_TEXT);
 
-$PAGE->set_url(new moodle_url('/grade/report/quick_edit/index.php', array(
-    'id' => $courseid,
-    'item' => $itemtype,
-    'itemid' => $itemid,
-    'group' => $groupid
-)));
-
 $course_params = array('id' => $courseid);
 
+$PAGE->set_url(new moodle_url('/grade/report/quick_edit/index.php', $course_params));
+
 if (!$course = $DB->get_record('course', $course_params)) {
     print_error('nocourseid');
 }
@@ -82,6 +77,11 @@ $pluginname = get_string('pluginname', 'gradereport_quick_edit');
 $report_url = new moodle_url('/grade/report/index.php', $course_params);
 $edit_url = new moodle_url('/grade/report/quick_edit/index.php', $course_params);
 
+$PAGE->navbar->ignore_active(true);
+
+$PAGE->navbar->add(get_string('courses'));
+$PAGE->navbar->add($course->shortname, new moodle_url('/course/view.php', $course_params));
+
 $PAGE->navbar->add(get_string('gradeadministration', 'grades'));
 $PAGE->navbar->add(get_string('pluginname', 'gradereport_grader'), $report_url);
 
diff --git a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
index 6d893ca..ff59be9 100755
--- a/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
+++ b/grade/report/quick_edit/lang/en/gradereport_quick_edit.php
@@ -23,7 +23,7 @@
 ///////////////////////////////////////////////////////////////////////////
 
 // General Strings
-$string['pluginname'] = 'Quick Edit report';
+$string['pluginname'] = 'Quick edit';
 $string['quick_edit:view'] = 'View the '.$string['pluginname'].' report';
 
 $string['exclude'] = 'Exclude';
-- 
1.7.1


From 97b358dd84edaf0015e09a88228e4df55f9f1065 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 10 Feb 2012 11:40:44 -0600
Subject: Consistent item names

---
 grade/report/quick_edit/screens/grade/lib.php |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/grade/report/quick_edit/screens/grade/lib.php b/grade/report/quick_edit/screens/grade/lib.php
index a4f9ff1..d9d5d96 100644
--- a/grade/report/quick_edit/screens/grade/lib.php
+++ b/grade/report/quick_edit/screens/grade/lib.php
@@ -102,6 +102,6 @@ class quick_edit_grade extends quick_edit_tablelike implements selectable_items
     }
 
     public function heading() {
-        return $this->item->itemname;
+        return $this->item->get_name();
     }
 }
-- 
1.7.1


From ab4bcd60208cada16fa66289302784d9c0a709ff Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Fri, 10 Feb 2012 11:41:23 -0600
Subject: Grader report quick edit integration.

---
 grade/report/grader/lang/en/gradereport_grader.php |    2 +
 grade/report/grader/lib.php                        |   40 +++++++++++++++++++-
 grade/report/grader/preferences_form.php           |    9 +++-
 grade/report/grader/settings.php                   |    6 +++
 4 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/grade/report/grader/lang/en/gradereport_grader.php b/grade/report/grader/lang/en/gradereport_grader.php
index 435f28b..427ba7c 100644
--- a/grade/report/grader/lang/en/gradereport_grader.php
+++ b/grade/report/grader/lang/en/gradereport_grader.php
@@ -32,3 +32,5 @@ $string['grader:manage'] = 'Manage the grader report';
 $string['grader:view'] = 'View the grader report';
 $string['pluginname'] = 'Grader report';
 $string['preferences'] = 'Grader report preferences';
+$string['quick_edit'] = 'Integrate Quick Edit';
+$string['quick_edit_desc'] = 'Creates _Quick edit_ links in the grader report.';
diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index bcacf6d..4e13660 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -570,6 +570,9 @@ class grade_report_grader extends grade_report {
         if (has_capability('gradereport/'.$CFG->grade_profilereport.':view', $this->context)) {
             $colspan++;
         }
+        if ($this->get_pref('integrate_quick_edit')) {
+            $colspan++;
+        }
         $colspan += count($extrafields);
 
         $levels = count($this->gtree->levels) - 1;
@@ -594,6 +597,9 @@ class grade_report_grader extends grade_report {
         if (has_capability('gradereport/'.$CFG->grade_profilereport.':view', $this->context)) {
             $studentheader->colspan = 2;
         }
+        if ($this->get_pref('integrate_quick_edit')) {
+            $studentheader->colspan++;
+        }
         $studentheader->text = $arrows['studentname'];
 
         $headerrow->cells[] = $studentheader;
@@ -644,6 +650,23 @@ class grade_report_grader extends grade_report {
 
             $userrow->cells[] = $usercell;
 
+            if ($this->get_pref('integrate_quick_edit')) {
+                $quickeditcell = new html_table_cell();
+                $quickeditcell->attributes['class'] = 'quickedituser';
+                $quickeditcell->header = true;
+                $a = new stdClass();
+                $a->user = fullname($user);
+                $strgradesforuser = get_string('gradesforuser', 'grades', $a);
+                $url = new moodle_url('/grade/report/quick_edit/index.php', array(
+                    'id' => $this->course->id,
+                    'item' => 'user',
+                    'itemid' => $user->id,
+                    'group' => $this->currentgroup
+                ));
+                $quickeditcell->text = html_writer::link($url, 'QE');
+                $userrow->cells[] = $quickeditcell;
+            }
+
             if (has_capability('gradereport/'.$CFG->grade_profilereport.':view', $this->context)) {
                 $userreportcell = new html_table_cell();
                 $userreportcell->attributes['class'] = 'userreport';
@@ -775,6 +798,21 @@ class grade_report_grader extends grade_report {
                         $arrow = $this->get_sort_arrow('move', $sortlink);
                     }
 
+                    if ($this->get_pref('integrate_quick_edit')) {
+                        $url = new moodle_url('/grade/report/quick_edit/index.php', array(
+                            'id' => $this->course->id,
+                            'item' => 'grade',
+                            'itemid' => $element['object']->id,
+                            'group' => $this->currentgroup
+                        ));
+                        $link = html_writer::link($url, ' QE ');
+                        $qe_link = html_writer::tag('span', $link, array(
+                            'class' => 'quickeditgrade'
+                        ));
+                    } else {
+                        $qe_link = '';
+                    }
+
                     $headerlink = $this->gtree->get_element_header($element, true, $this->get_pref('showactivityicons'), false);
 
                     $itemcell = new html_table_cell();
@@ -785,7 +823,7 @@ class grade_report_grader extends grade_report {
                     }
 
                     $itemcell->colspan = $colspan;
-                    $itemcell->text = shorten_text($headerlink) . $arrow;
+                    $itemcell->text = $qe_link . shorten_text($headerlink) . $arrow;
                     $itemcell->header = true;
                     $itemcell->scope = 'col';
 
diff --git a/grade/report/grader/preferences_form.php b/grade/report/grader/preferences_form.php
index 93f4c03..85c6cec 100644
--- a/grade/report/grader/preferences_form.php
+++ b/grade/report/grader/preferences_form.php
@@ -97,6 +97,7 @@ class grader_report_preferences_form extends moodleform {
         // quickgrading and showquickfeedback are conditional on grade:edit capability
         if (has_capability('moodle/grade:edit', $context)) {
             $preferences['prefgeneral']['quickgrading'] = $checkbox_default;
+            $preferences['prefgeneral']['integrate_quick_edit'] = $checkbox_default;
             $preferences['prefgeneral']['showquickfeedback'] = $checkbox_default;
         }
 
@@ -169,10 +170,14 @@ class grader_report_preferences_form extends moodleform {
                     $options[GRADE_REPORT_PREFERENCE_DEFAULT] = get_string('reportdefault', 'grades', $default);
                 }
 
-                $label = get_string($lang_string, 'grades') . $number;
+                if ($lang_string == 'integrate_quick_edit') {
+                    $label = get_string('quick_edit', 'gradereport_grader');
+                } else {
+                    $label = get_string($lang_string, 'grades') . $number;
+                }
 
                 $mform->addElement($type, $full_pref, $label, $options);
-                if ($lang_string != 'showuserimage') {
+                if ($lang_string != 'showuserimage' and $lang_string != 'integrate_quick_edit') {
                     $mform->addHelpButton($full_pref, $lang_string, 'grades');
                 }
                 $mform->setDefault($full_pref, $pref_value);
diff --git a/grade/report/grader/settings.php b/grade/report/grader/settings.php
index c795b33..d5d06f8 100644
--- a/grade/report/grader/settings.php
+++ b/grade/report/grader/settings.php
@@ -31,6 +31,12 @@ if ($ADMIN->fulltree) {
     $settings->add(new admin_setting_configcheckbox('grade_report_quickgrading', get_string('quickgrading', 'grades'),
                                                 get_string('quickgrading_help', 'grades'), 1));
 
+    $settings->add(new admin_setting_configcheckbox(
+        'grade_report_integrate_quick_edit',
+        get_string('quick_edit', 'gradereport_grader'),
+        get_string('quick_edit_desc', 'gradereport_grader'), 0
+    ));
+
     $settings->add(new admin_setting_configcheckbox('grade_report_showquickfeedback', get_string('quickfeedback', 'grades'),
                                                 get_string('showquickfeedback_help', 'grades'), 0));
 
-- 
1.7.1


From 091dca8d029c3927dad46003f958dc1726cb439d Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 15 Feb 2012 09:35:12 -0600
Subject: Add tab index support on table format

---
 grade/report/quick_edit/classes/lib.php   |   22 ++++++++++--
 grade/report/quick_edit/classes/uilib.php |   52 ++++++++++++++++++++++++-----
 2 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/grade/report/quick_edit/classes/lib.php b/grade/report/quick_edit/classes/lib.php
index c5f0d9b..6b62600 100644
--- a/grade/report/quick_edit/classes/lib.php
+++ b/grade/report/quick_edit/classes/lib.php
@@ -184,16 +184,23 @@ abstract class quick_edit_screen {
     }
 }
 
-abstract class quick_edit_tablelike extends quick_edit_screen {
+abstract class quick_edit_tablelike extends quick_edit_screen implements tabbable {
     var $items;
 
     public abstract function headers();
 
     public abstract function format_line($item);
 
+    public function get_tabindex() {
+        return (count($this->definition()) * $this->total) + $this->index;
+    }
+
     public function format_definition($line, $grade) {
-        foreach ($this->definition() as $field) {
-            $html = $this->factory()->create($field)->format($grade);
+        foreach ($this->definition() as $i => $field) {
+            // Table tab index
+            $tab = ($i * $this->total) + $this->index;
+
+            $html = $this->factory()->create($field)->format($grade, $tab);
 
             if ($field == 'finalgrade') {
                 $html .= $this->structure->get_grade_analysis_icon($grade);
@@ -212,7 +219,12 @@ abstract class quick_edit_tablelike extends quick_edit_screen {
 
         $table->data = array();
 
+        // To be used for extra formatting
+        $this->index = 0;
+        $this->total = count($this->items);
+
         foreach ($this->items as $item) {
+            $this->index ++;
             $table->data[] = $this->format_line($item);
         }
 
@@ -229,7 +241,9 @@ abstract class quick_edit_tablelike extends quick_edit_screen {
 
     public function buttons() {
         $save = html_writer::empty_tag('input', array(
-            'type' => 'submit', 'value' => get_string('update')
+            'type' => 'submit',
+            'value' => get_string('update'),
+            'tabindex' => $this->get_tabindex()
         ));
 
         return array($save);
diff --git a/grade/report/quick_edit/classes/uilib.php b/grade/report/quick_edit/classes/uilib.php
index 8dd1cb4..e64b148 100644
--- a/grade/report/quick_edit/classes/uilib.php
+++ b/grade/report/quick_edit/classes/uilib.php
@@ -19,8 +19,11 @@ class quick_edit_factory_class_wrap {
         $this->class = $class;
     }
 
-    function format($what) {
-        return new $this->class($what);
+    function format() {
+        $args = func_get_args();
+
+        $reflect = new ReflectionClass($this->class);
+        return $reflect->newInstanceArgs($args);
     }
 }
 
@@ -64,9 +67,11 @@ class quick_edit_empty_element extends quick_edit_ui_element {
 
 class quick_edit_text_attribute extends quick_edit_ui_element {
     var $is_disabled;
+    var $tabindex;
 
-    function __construct($name, $value, $is_disabled = false) {
+    function __construct($name, $value, $is_disabled = false, $tabindex = null) {
         $this->is_disabled = $is_disabled;
+        $this->tabindex = $tabindex;
         parent::__construct($name, $value);
     }
 
@@ -81,6 +86,10 @@ class quick_edit_text_attribute extends quick_edit_ui_element {
             'value' => $this->value
         );
 
+        if (!empty($this->tabindex)) {
+            $attributes['tabindex'] = $this->tabindex;
+        }
+
         if ($this->is_disabled) {
             $attributes['disabled'] = 'DISABLED';
         }
@@ -100,9 +109,11 @@ class quick_edit_text_attribute extends quick_edit_ui_element {
 
 class quick_edit_checkbox_attribute extends quick_edit_ui_element {
     var $is_checked;
+    var $tabindex;
 
-    function __construct($name, $is_checked = false) {
+    function __construct($name, $is_checked = false, $tabindex = null) {
         $this->is_checked = $is_checked;
+        $this->tabindex = $tabindex;
         parent::__construct($name, 1);
     }
 
@@ -128,6 +139,10 @@ class quick_edit_checkbox_attribute extends quick_edit_ui_element {
             'name' => 'old' . $this->name
         );
 
+        if (!empty($this->tabindex)) {
+            $attributes['tabindex'] = $this->tabindex;
+        }
+
         if ($this->is_checked) {
             $attributes['checked'] = 'CHECKED';
             $hidden['value'] = 1;
@@ -149,17 +164,30 @@ abstract class quick_edit_attribute_format {
     }
 }
 
-abstract class quick_edit_grade_attribute_format extends quick_edit_attribute_format implements unique_name {
+abstract class quick_edit_grade_attribute_format extends quick_edit_attribute_format implements unique_name, tabbable {
     var $name;
 
-    function __construct($grade) {
-        $this->grade = $grade;
+    function __construct() {
+        $args = func_get_args();
+
+        $this->get_arg_or_nothing($args, 0, 'grade');
+        $this->get_arg_or_nothing($args, 1, 'tabindex');
     }
 
     function get_name() {
         return "{$this->name}_{$this->grade->itemid}_{$this->grade->userid}";
     }
 
+    function get_tabindex() {
+        return isset($this->tabindex) ? $this->tabindex : null;
+    }
+
+    private function get_arg_or_nothing($args, $index, $field) {
+        if (isset($args[$index])) {
+            $this->$field = $args[$index];
+        }
+    }
+
     public abstract function set($value);
 }
 
@@ -179,6 +207,10 @@ interface be_checked {
     function is_checked();
 }
 
+interface tabbable {
+    function get_tabindex();
+}
+
 class quick_edit_finalgrade_ui extends quick_edit_grade_attribute_format implements unique_value, be_disabled {
 
     var $name = 'finalgrade';
@@ -200,7 +232,8 @@ class quick_edit_finalgrade_ui extends quick_edit_grade_attribute_format impleme
         return new quick_edit_text_attribute(
             $this->get_name(),
             $this->get_value(),
-            $this->is_disabled()
+            $this->is_disabled(),
+            $this->get_tabindex()
         );
     }
 
@@ -269,7 +302,8 @@ class quick_edit_feedback_ui extends quick_edit_grade_attribute_format implement
         return new quick_edit_text_attribute(
             $this->get_name(),
             $this->get_value(),
-            $this->is_disabled()
+            $this->is_disabled(),
+            $this->get_tabindex()
         );
     }
 
-- 
1.7.1


From 62ee9e7a9f7ddd18974d7a74e8c41f216da0bae8 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 15 Feb 2012 09:37:26 -0600
Subject: Add Suggested CSS

---
 grade/report/quick_edit/styles.css |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)
 create mode 100644 grade/report/quick_edit/styles.css

diff --git a/grade/report/quick_edit/styles.css b/grade/report/quick_edit/styles.css
new file mode 100644
index 0000000..9952d05
--- /dev/null
+++ b/grade/report/quick_edit/styles.css
@@ -0,0 +1,15 @@
+#page-grade-report-quick_edit-index div.generalbox {
+  margin: 0 20px 15px 20px;
+}
+
+#page-grade-report-quick_edit-index div.generalbox div.singleselect form div {
+  text-align: center;
+}
+
+#page-grade-report-quick_edit-index div.generalbox table.generaltable {
+  margin: 0 auto 15px auto;
+}
+
+#page-grade-report-quick_edit-index div.generalbox form div {
+  text-align: center;
+}
-- 
1.7.1


From 2bcd81ee9ccb8de4751048eea124771d7e377a99 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 15 Feb 2012 12:39:58 -0600
Subject: Option to repeat gradebook headers

---
 grade/report/grader/lib.php              |   26 ++++++++++++++++++++++++--
 grade/report/grader/preferences_form.php |    1 +
 grade/report/grader/settings.php         |    3 +++
 lang/en/grades.php                       |    2 ++
 4 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index bcacf6d..e42c78b 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -614,11 +614,23 @@ class grade_report_grader extends grade_report {
 
         $rowclasses = array('even', 'odd');
 
+        $repeat = $this->get_pref('repeatheaders');
+
+        // Repeat filler
+        $repeatentries = unserialize(serialize($rows));
+
         $suspendedstring = null;
         foreach ($this->users as $userid => $user) {
+            if ($this->rowcount > 0 and $this->rowcount % $repeat == 0) {
+                $rows = array_merge($rows, $repeatentries);
+            }
+
+            $this->rowcount++;
+
             $userrow = new html_table_row();
+
             $userrow->id = 'fixed_user_'.$userid;
-            $userrow->attributes['class'] = 'r'.$this->rowcount++.' '.$rowclasses[$this->rowcount % 2];
+            $userrow->attributes['class'] = $rowclasses[$this->rowcount % 2];
 
             $usercell = new html_table_cell();
             $usercell->attributes['class'] = 'user';
@@ -711,6 +723,7 @@ class grade_report_grader extends grade_report {
             $headingrow->attributes['class'] = 'heading_name_row';
 
             foreach ($row as $columnkey => $element) {
+
                 $sortlink = clone($this->baseurl);
                 if (isset($element['object']->id)) {
                     $sortlink->param('sortitemid', $element['object']->id);
@@ -822,8 +835,17 @@ class grade_report_grader extends grade_report {
 
         $rowclasses = array('even', 'odd');
 
+        $repeat = $this->get_pref('repeatheaders');
+
+        // Headers to repeat
+        $repeatentries = unserialize(serialize($rows));
+
         foreach ($this->users as $userid => $user) {
 
+            if ($this->rowcount > 0 and $this->rowcount % $repeat == 0) {
+                $rows = array_merge($rows, $repeatentries);
+            }
+
             if ($this->canviewhidden) {
                 $altered = array();
                 $unknown = array();
@@ -835,6 +857,7 @@ class grade_report_grader extends grade_report {
             }
 
 
+            $this->rowcount++;
             $itemrow = new html_table_row();
             $itemrow->id = 'user_'.$userid;
             $itemrow->attributes['class'] = $rowclasses[$this->rowcount % 2];
@@ -1065,7 +1088,6 @@ class grade_report_grader extends grade_report {
 
         $html = '';
 
-
         if ($fixedstudents) {
             $fixedcolumntable = new html_table();
             $fixedcolumntable->id = 'fixed_column';
diff --git a/grade/report/grader/preferences_form.php b/grade/report/grader/preferences_form.php
index 93f4c03..3066b7b 100644
--- a/grade/report/grader/preferences_form.php
+++ b/grade/report/grader/preferences_form.php
@@ -103,6 +103,7 @@ class grader_report_preferences_form extends moodleform {
         // View capability is the lowest permission. Users with grade:manage or grade:edit must also have grader:view
         if (has_capability('gradereport/grader:view', $context)) {
             $preferences['prefgeneral']['studentsperpage'] = 'text';
+            $preferences['prefgeneral']['repeatheaders'] = 'text';
             $preferences['prefgeneral']['aggregationposition'] = array(GRADE_REPORT_PREFERENCE_DEFAULT => '*default*',
                                                                        GRADE_REPORT_AGGREGATION_POSITION_FIRST => get_string('positionfirst', 'grades'),
                                                                        GRADE_REPORT_AGGREGATION_POSITION_LAST => get_string('positionlast', 'grades'));
diff --git a/grade/report/grader/settings.php b/grade/report/grader/settings.php
index c795b33..6e1fff5 100644
--- a/grade/report/grader/settings.php
+++ b/grade/report/grader/settings.php
@@ -28,6 +28,9 @@ if ($ADMIN->fulltree) {
     $settings->add(new admin_setting_configtext('grade_report_studentsperpage', get_string('studentsperpage', 'grades'),
                                             get_string('studentsperpage_help', 'grades'), 100));
 
+    $settings->add(new admin_setting_configtext('grade_report_repeatheaders', get_string('repeatheaders', 'grades'),
+                                            get_string('repeatheaders_help', 'grades'), 10));
+
     $settings->add(new admin_setting_configcheckbox('grade_report_quickgrading', get_string('quickgrading', 'grades'),
                                                 get_string('quickgrading_help', 'grades'), 1));
 
diff --git a/lang/en/grades.php b/lang/en/grades.php
index b583eff..79519e2 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -509,6 +509,8 @@ $string['realpercentage'] = 'Real (percentage)';
 $string['regradeanyway'] = 'Regrade anyway';
 $string['removeallcoursegrades'] = 'Delete all grades';
 $string['removeallcourseitems'] = 'Delete all items and categories';
+$string['repeatheaders'] = 'Repeat Headers';
+$string['repeatheaders_help'] = 'Repeat gradebook headers after this many rows.';
 $string['report'] = 'Report';
 $string['reportdefault'] = 'Report default ({$a})';
 $string['reportplugins'] = 'Report plugins';
-- 
1.7.1


From bbde27da74f343a69a205c0feb9b844e2fbd0d27 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 15 Feb 2012 13:57:19 -0600
Subject: Curve to checkbox should adhere to rawgrade check

---
 grade/edit/tree/item_form.php |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/grade/edit/tree/item_form.php b/grade/edit/tree/item_form.php
index e16fa42..be1ecef 100644
--- a/grade/edit/tree/item_form.php
+++ b/grade/edit/tree/item_form.php
@@ -226,6 +226,10 @@ class edit_item_form extends moodleform {
             if (!$grade_item->is_raw_used()) {
                 $mform->removeElement('plusfactor');
                 $mform->removeElement('multfactor');
+
+                if ($mform->elementExists('curve_to')) {
+                    $mform->removeElement('curve_to');
+                }
             }
 
             if ($grade_item->is_outcome_item()) {
-- 
1.7.1


From 52b839d0f0b97a0ddd3b53f8f70b66a08a1d007a Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 15 Feb 2012 14:55:42 -0600
Subject: Admin option now present

---
 grade/report/grader/lib.php              |    8 ++++++--
 grade/report/grader/preferences_form.php |    1 +
 grade/report/grader/settings.php         |    3 +++
 lang/en/grades.php                       |    2 ++
 4 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index 6714bfb..4643ca4 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -703,6 +703,8 @@ class grade_report_grader extends grade_report {
         );
         $jsscales = array();
 
+        $render_percents = $this->get_pref('showweightedpercents');
+
         foreach ($this->gtree->get_levels() as $key=>$row) {
             if ($key == 0) {
                 // do not display course grade category
@@ -782,14 +784,16 @@ class grade_report_grader extends grade_report {
                     $itemcell = new html_table_cell();
                     $itemcell->attributes['class'] = $type . ' ' . $catlevel . 'highlightable';
 
-                    $percents = $this->get_weighted_percents($element['object']);
+                    $percents = $render_percents ?
+                        $this->get_weighted_percents($element['object']) : '';
 
                     if ($element['object']->is_hidden()) {
                         $itemcell->attributes['class'] .= ' hidden';
                     }
 
                     $itemcell->colspan = $colspan;
-                    $itemcell->text = shorten_text($headerlink) . $percents . $arrow;
+                    $itemcell->text = shorten_text($headerlink);
+                    $itemcell->text .= $percents . $arrow;
                     $itemcell->header = true;
                     $itemcell->scope = 'col';
 
diff --git a/grade/report/grader/preferences_form.php b/grade/report/grader/preferences_form.php
index 93f4c03..ae0465f 100644
--- a/grade/report/grader/preferences_form.php
+++ b/grade/report/grader/preferences_form.php
@@ -112,6 +112,7 @@ class grader_report_preferences_form extends moodleform {
             $preferences['prefshow']['showactivityicons'] = $checkbox_default;
             $preferences['prefshow']['showranges'] = $checkbox_default;
             $preferences['prefshow']['showanalysisicon'] = $checkbox_default;
+            $preferences['prefshow']['showweightedpercents'] = $checkbox_default;
 
             if ($canviewhidden) {
                 $preferences['prefrows']['shownumberofgrades'] = $checkbox_default;
diff --git a/grade/report/grader/settings.php b/grade/report/grader/settings.php
index c795b33..b0fb597 100644
--- a/grade/report/grader/settings.php
+++ b/grade/report/grader/settings.php
@@ -63,6 +63,9 @@ if ($ADMIN->fulltree) {
     $settings->add(new admin_setting_configcheckbox('grade_report_showanalysisicon', get_string('showanalysisicon', 'core_grades'),
                                                 get_string('showanalysisicon_desc', 'core_grades'), 1));
 
+    $settings->add(new admin_setting_configcheckbox('grade_report_showweightedpercents', get_string('showweightedpercents', 'grades'),
+        get_string('showweightedpercents_help', 'grades'), 0));
+
     $settings->add(new admin_setting_configcheckbox('grade_report_showuserimage', get_string('showuserimage', 'grades'),
                                                 get_string('showuserimage_help', 'grades'), 1));
 
diff --git a/lang/en/grades.php b/lang/en/grades.php
index b583eff..eefe099 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -588,6 +588,8 @@ $string['showrank_help'] = 'Show the position of the student in relation to the
 $string['showuserimage'] = 'Show user profile images';
 $string['showuserimage_help'] = 'Whether to show the user\'s profile image next to the name in the grader report.';
 $string['showverbose'] = 'Show {$a->category} {$a->itemmodule} {$a->itemname}';
+$string['showweightedpercents'] = 'Show weighted percents';
+$string['showweightedpercents_help'] = "Show the item's weight in percent of a weighted category type.";
 $string['simpleview'] = 'Simple view';
 $string['sitewide'] = 'Site-wide';
 $string['sort'] = 'sort';
-- 
1.7.1


From 096fb5ab746ca598bdd7eb2f2cc85a28929687fc Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 15 Feb 2012 14:58:47 -0600
Subject: QE link now on it's own line.

---
 grade/report/grader/lib.php |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index 4e13660..6af4de5 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -823,7 +823,8 @@ class grade_report_grader extends grade_report {
                     }
 
                     $itemcell->colspan = $colspan;
-                    $itemcell->text = $qe_link . shorten_text($headerlink) . $arrow;
+                    $itemcell->text = $qe_link;
+                    $itemcell->text .= shorten_text($headerlink) . $arrow;
                     $itemcell->header = true;
                     $itemcell->scope = 'col';
 
-- 
1.7.1


From 0c1d622d7d3e193dd109a1fde1f8b6ce06063801 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 7 Dec 2011 14:18:25 -0600
Subject: Grade library now supports manual rawgrade

---
 grade/edit/tree/item_form.php |    5 -----
 grade/report/grader/lib.php   |    5 +++++
 lib/grade/grade_item.php      |   14 +++++++++-----
 3 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/grade/edit/tree/item_form.php b/grade/edit/tree/item_form.php
index 642be6b..412b206 100644
--- a/grade/edit/tree/item_form.php
+++ b/grade/edit/tree/item_form.php
@@ -281,11 +281,6 @@ class edit_item_form extends moodleform {
                     }
                 }
             }
-
-        } else {
-            // all new items are manual, children of course category
-            $mform->removeElement('plusfactor');
-            $mform->removeElement('multfactor');
         }
 
         // no parent header for course category
diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index 6af4de5..bbd9357 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -965,6 +965,11 @@ class grade_report_grader extends grade_report {
 
                 } else if ($USER->gradeediting[$this->courseid]) {
 
+                    // Editing means user edit manual item raw
+                    if ($item->is_manual_item()) {
+                        $gradeval = $grade->rawgrade;
+                    }
+
                     if ($item->scaleid && !empty($scalesarray[$item->scaleid])) {
                         $scale = $scalesarray[$item->scaleid];
                         $gradeval = (int)$gradeval; // scales use only integers
diff --git a/lib/grade/grade_item.php b/lib/grade/grade_item.php
index 630e915..0e60942 100644
--- a/lib/grade/grade_item.php
+++ b/lib/grade/grade_item.php
@@ -655,10 +655,6 @@ class grade_item extends grade_object {
                 return "Could not aggregate final grades for category:".$this->id; // TODO: improve and localize
             }
 
-        } else if ($this->is_manual_item()) {
-            // manual items track only final grades, no raw grades
-            return true;
-
         } else if (!$this->is_raw_used()) {
             // hmm - raw grades are not used- nothing to regrade
             return true;
@@ -935,7 +931,7 @@ class grade_item extends grade_object {
      * @return boolean
      */
     public function is_raw_used() {
-        return ($this->is_external_item() and !$this->is_calculated() and !$this->is_outcome_item());
+        return ($this->is_manual_item() or $this->is_external_item() and !$this->is_calculated() and !$this->is_outcome_item());
     }
 
     /**
@@ -1438,6 +1434,14 @@ class grade_item extends grade_object {
             return false;
         }
 
+        // Manual Item raw-grade support
+        if ($this->is_manual_item()) {
+            return $this->update_raw_grade(
+                $userid, $finalgrade, $source, $feedback, $feedbackformat,
+                $usermodified, null, null, $grade
+            );
+        }
+
         $oldgrade = new stdClass();
         $oldgrade->finalgrade     = $grade->finalgrade;
         $oldgrade->overridden     = $grade->overridden;
-- 
1.7.1


From b6ac73c068802a03bd967a1bdd66f072a2ce36fd Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 7 Dec 2011 14:25:59 -0600
Subject: Upgrade script for old manual items

---
 grade/report/grader/db/upgrade.php |   69 ++++++++++++++++++++++++++++++++++++
 grade/report/grader/version.php    |    3 +-
 2 files changed, 71 insertions(+), 1 deletions(-)
 create mode 100644 grade/report/grader/db/upgrade.php

diff --git a/grade/report/grader/db/upgrade.php b/grade/report/grader/db/upgrade.php
new file mode 100644
index 0000000..9cdbb4f
--- /dev/null
+++ b/grade/report/grader/db/upgrade.php
@@ -0,0 +1,69 @@
+<?php
+
+function xmldb_gradereport_grader_upgrade($oldversion) {
+
+    $upgrade = new gradereport_grader_upgrade(array(
+        new grader_manual_items()
+    ));
+
+    return $upgrade->from($oldversion);
+}
+
+abstract class gradereport_grader_upgrade_state {
+    var $version;
+
+    abstract function upgrade($db);
+
+    function __invoke($db) {
+        return $this->upgrade($db);
+    }
+}
+
+class grader_manual_items extends gradereport_grader_upgrade_state {
+    var $version = 2011120801;
+
+    function upgrade($db) {
+        $sql = "UPDATE {grade_grades} gr, {grade_items} gi
+            SET gr.rawgrade = gr.finalgrade
+            WHERE gi.id = gr.itemid AND gi.itemtype = 'manual'";
+
+        return $db->execute($sql);
+    }
+}
+
+class gradereport_grader_upgrade {
+    function __construct($upgrades) {
+        $this->upgrades = $upgrades;
+    }
+
+    function from($oldversion) {
+        global $DB;
+
+        // Oldest upgrade first
+        usort($this->upgrades, function($a, $b) {
+            $diff = ($a->version < $b->version) ? -1 : 1;
+            return ($a->version == $b->version) ? 0 : $diff;
+        });
+
+        $result = true;
+
+        foreach ($this->upgrades as $upgrade) {
+            if (!$result) continue;
+
+            if ($oldversion < $upgrade->version and is_callable($upgrade)) {
+
+                try {
+                    $success = $upgrade($DB);
+
+                    $result = ($result and $success);
+                } catch (Exception $e) {
+                    $result = false;
+                }
+
+                upgrade_plugin_savepoint($result, $upgrade->version, 'gradereport', 'grader');
+            }
+        }
+
+        return $result;
+    }
+}
diff --git a/grade/report/grader/version.php b/grade/report/grader/version.php
index 14c2e50..bf50771 100644
--- a/grade/report/grader/version.php
+++ b/grade/report/grader/version.php
@@ -25,6 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2011112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2011120801;
 $plugin->requires  = 2011112900;        // Requires this Moodle version
 $plugin->component = 'gradereport_grader'; // Full name of the plugin (used for diagnostics)
+
-- 
1.7.1


From 7919b00d863350c29099cf9197543ff5b0f70b4c Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Tue, 13 Dec 2011 13:15:49 -0600
Subject: Fixed SQL problem on postgreSQL databases.

---
 grade/report/grader/db/upgrade.php |   17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/grade/report/grader/db/upgrade.php b/grade/report/grader/db/upgrade.php
index 9cdbb4f..c4af5cd 100644
--- a/grade/report/grader/db/upgrade.php
+++ b/grade/report/grader/db/upgrade.php
@@ -23,11 +23,20 @@ class grader_manual_items extends gradereport_grader_upgrade_state {
     var $version = 2011120801;
 
     function upgrade($db) {
-        $sql = "UPDATE {grade_grades} gr, {grade_items} gi
-            SET gr.rawgrade = gr.finalgrade
-            WHERE gi.id = gr.itemid AND gi.itemtype = 'manual'";
+        $base_sql = "%s {grade_grades} gr, {grade_items} gi %s " .
+            "WHERE gi.id = gr.itemid AND gi.itemtype = 'manual'";
 
-        return $db->execute($sql);
+        $sql = sprintf($base_sql, "SELECT COUNT(*) FROM", "");
+
+        $count = $db->count_records_sql($sql);
+
+        if (empty($count)) {
+            return true;
+        } else {
+            $sql = sprintf($base_sql, "UPDATE", "SET gr.rawgrade = gr.finalgrade");
+
+            return $db->execute($sql);
+        }
     }
 }
 
-- 
1.7.1


From e0128485810ec0b8696a84e75dbb2ac27de09ca4 Mon Sep 17 00:00:00 2001
From: Philip Cali <philip.cali@gmail.com>
Date: Wed, 15 Feb 2012 10:07:45 -0600
Subject: Quick edit considers manual item rawgrade

---
 grade/report/quick_edit/classes/uilib.php |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/grade/report/quick_edit/classes/uilib.php b/grade/report/quick_edit/classes/uilib.php
index e64b148..98c8a80 100644
--- a/grade/report/quick_edit/classes/uilib.php
+++ b/grade/report/quick_edit/classes/uilib.php
@@ -216,9 +216,11 @@ class quick_edit_finalgrade_ui extends quick_edit_grade_attribute_format impleme
     var $name = 'finalgrade';
 
     function get_value() {
-        return $this->grade->finalgrade ?
-            format_float($this->grade->finalgrade, $this->grade->grade_item->get_decimals()) :
-            '';
+        // Manual item raw grade support
+        $val = $this->grade->grade_item->is_manual_item() ?
+            $this->grade->rawgrade : $this->grade->finalgrade;
+
+        return $val ? format_float($val, $this->grade->grade_item->get_decimals()) : '';
     }
 
     function is_disabled() {
-- 
1.7.1

